Training modules/Documentation

Creating Training Modules on the Program and Events Dashboard



This guide will walk you through creating new training modules on the Program and Events Dashboard. These are especially useful as teaching materials at events or workshops (because of the ability to add a quiz or show the user how much progress they’ve made so far), or just when you want to put out materials that you think would be useful to others in the movement.

Many of the examples in this documentation are taken from the Wikimedia Foundation Support and Safety team's training modules, developed between July 2016 and June 2017. This documentation was written by Omar Shehata and Joe Sutherland.

The Program and Events Dashboard pulls content from Meta-Wiki directly once it is set up. This means that content exists entirely on Meta-Wiki and can be edited and translated there directly.

General structure


While the Dashboard pulls in content from Meta-Wiki, a structure needs to be set up to tell it what to do. This is done with a set of JSON files. JSON is a markup language for sets of data that is designed to be easy for both humans and computers to read. These tell the dashboard which Meta-Wiki pages to use, the order to use them in, and some additional information (such as titles and descriptions of modules).

The configuration files for the current set of Training Modules can be found at Training modules/dashboard.



It is important to note that the dashboard does not actually support wiki pages or embed the content directly. Instead, it generates these pages by attempting to parse the wiki markup and generating the correct HTML. What you see onwiki will not exactly reflect how it will look on the page.

Creating the elements


Layout in a nutshell


The training modules are laid out like this:

  • Library
    • Module 1
      • Slide 1
      • Slide 2
      • Slide 3...
    • Module 2
      • Slide 1
      • Slide 2
      • Slide 3...

How this works


Each box you see on the training dashboard is a library. Each library contains a set of modules, and each module contains a set of slides. So there are three distinct types of JSON files.

It is recommended that the JSON files be created under your own user namespace; the MediaWiki software will automagically detect that you are editing a script, and generate a nicer editing window for this. In theory, though, they could be stored anywhere. Add a link to them in the pages below.

Step 1: Libraries


The library JSON files live here. This is an example for the Support and Safety library. Here's a breakdown of what it looks like:

   "id": "10001",
   "name": "Support and Safety",
   "slug": "support-and-safety",
   "introduction": "Support and Safety training modules",
  • The id should be a 5 digit unique number.
    • When creating JSON for libraries, begin with 10001 and count up. It's likely you'll only ever have to deal with one library at a time.
    • If you’re creating JSON files for a new library, start by looking at the id of the previous library file, and increment that by 1 for your own library.
  • The name is the title of the library. This is displayed in several of the messages around the Dashboard, such as in the navigation bars.
  • A slug is a short-form name for the library. This will form part of the URL, and should be unique. It should be in all lower caps and words separated by dashes.
   "categories": [
           "title": "Keeping events safe",
           "description": "Training modules for people running in-person events",
           "modules": [
                   "slug": "keeping-events-safe",
                   "name": "Keeping events safe — event organizers",
                   "description": "Training to prepare event organizers to handle incidents of harassment or abuse."
  • The categories section is used to list the modules.
    • They can be further grouped together into separate categories.
  • At the innermost level, the module object has a slug, name and description.
    • The slug works the same way as the library slug. It acts as a unique identifier and forms part of the module's URL.
    • The name is displayed in several places, such as menus and navigation bars.
    • The description is displayed in several navigational contexts, such as the library's homepage.
           "title": "Dealing with online harassment",
           "description": "Training modules for Wikimedia project functionaries and others who might deal with harassment, be it short-term or involving cases",
           "modules": [
                   "slug": "dealing-with-online-harassment-fundamentals",
                   "name": "Dealing with online harassment: Fundamentals",
                   "description": "Fundamentals of dealing with abuse – what is harassment, and how can you respond to it immediately?"
                   "slug": "dealing-with-online-harassment-other-forms",
                   "name": "Dealing with online harassment: Other forms of harassment",
                   "description": "Other forms of harassment, what they involve, and how they can be immediately dealt with. This is information that will be useful when you are fielding reports."
  • The modules label here is used to introduce an array, signified by the square brackets - [ ].

Remember to close out your JSON. Use the same symbol to close as you used to open. Indenting with four spaces (or a tab) can help to keep track of what is and isn't closed.

Step 2: Modules


Modules are the next level down from libraries – these are what actually store the slides themselves. Consider them the "chapters" of the actual training module pages.

The next step therefore is to create the module JSON. Some examples can be found here – this documentation will refer to the module called Dealing with Harassment: Fundamentals.

   "id": 10002,
   "name": "Dealing with online harassment: Fundamentals",
   "slug": "dealing-with-online-harassment-fundamentals",
   "description": "Welcome! This is the first of five modules about dealing with online harassment. This module should take around ten minutes to complete.\n\nThis section covers the fundamentals of dealing with abuse – what harassment is and how you can respond to it immediately.",
  • The id has to match the library id it belongs to.
    • When creating JSON for modules, begin with 10001 and count up. This is the second module in the library, and so is assigned the number 10002.
  • The slug should also match the slug you used when defining it in the library JSON.
    • Usually this will be the name with symbols removed, and with dashes instead of spaces, just like the library's slug. It is displayed in the URL:
  • The description will be displayed on the landing page for the module. It should provide a summary of the slide content, and be formatted in a way that will be parsed correctly – this means making use of "escape characters" such as the \n in the example above, which creates a new line. (Other common escapes include \' and \" for apostrophes and quotation marks.)
   "slides": [
           "slug": "purpose-of-this-module-2"
           "slug": "what-is-harassment"
           "slug": "why-do-you-need-to-care-about-harassment"
           "slug": "some-common-forms-of-harassment-on-our-projects"
           "slug": "blocking-users"
           "slug": "revision-deletion-or-suppression"
           "slug": "cross-wiki-blocking-and-tracking"
  • The slides array is just a list of slugs, again within a JSON array.

Step 3: Slides


There are two methods for creating slides; either works, though the first here is more straightforward.

New method


Once your module is defined with its slides, you can move onto the slides. Whereas before, a JSON file had to be created for each slide, this is no longer required.

To make this method work, the id number for the slide – which must be unique among all slides – is included on the title of the new slide's page itself. So, it would look like this:


  • The id (in green) is the unique id of the slide. It needs to be unique among all slides that exist on the dashboard; the easiest way to ensure this is to follow your module's format.
    • So, this module (102XX) would imply that all slides from 102XX to 102XX are fair game. The order of these numbers doesn't matter – more on that later.
  • The slug (in blue) will be displayed as the URL on the dashboard itself.

The order of these slides depends on its placement on the respective list on Training modules/dashboard/slides. Create a section for your new library, and document your module's layout underneath. To use the example of Wikipedia Essentials:

== Editing ==
; Wikipedia Essentials
Slide ids: 103XX

* [[Training modules/dashboard/slides/10301-policies-and-guidelines-basic-overview]]
* [[Training modules/dashboard/slides/10302-five-pillars]]

Use a unique sequence of numbers for your module id. If you need more than a hundred slides, use a number that will allow you to surpass that hundred (e.g. 123XX and 124XX). It's usually a good idea to use an id number that matches the module number in general – for example, a module with id 10003 might use slides numbered 103XX.

Legacy JSON method


Older technique involving more JSON - this is no longer necessary, but will still function.

Once your module is defined with its slides, you can move onto the slide JSON. A list of the JSON files that make up the Support and Safety training modules can be found here.

The slide JSON only has 3 items, and looks like this:

   "id": 10201,
   "slug": "purpose-of-this-module-2",
   "wiki_page": "Training_modules/Dealing_with_online_harassment/slides/purpose-of-this-module-2"
  • The id has to be unique. It is generally advisable to use the pattern XYYZZ where:
    • X = the number of the library, in this case 1
    • YY = the number of the module, in this case 02
    • ZZ = the number of the slide, in this case 01
  • The slug has to match what you defined in your module (as well as the actual url of the wiki page the JSON lives on; this one is located at User:JSutherland_(WMF)/dashboard_slides/purpose-of-this-module-2.json )
  • The wiki_page should be the relative URL of the page you want to embed for this slide. This is where the actual text for the module will be located and is what the dashboard will pull from when rendering the actual slide.

Note: If your wiki_page url contains any special characters, make sure to include the actual character and NOT its hex value. For example, a URL containing the string one & two would become one_%26_two. Use the first one, not the second one, in your JSON file.

That’s it! Once you’ve created your library JSON file, all your module JSON files, your slide JSON files, and your slide content itself, you should be ready to test the new modules on the dashboard.

Formatting slides


Now that the JSON files are in place, the actual slide content can be written and developed. Ideally, the content should be drafted and finalised in advance so that it can be more easily split across the slides.

While the dashboard tries to parse wiki markup to generate training slides, it is not yet fully able to support wiki markup. There are many edge cases that the script will not be ready to cope with yet. You can take a look at exactly the parsing steps it takes in the source code, available on Github.

The script will pull in everything from the page and parse it accordingly. Things to bear in mind while you are creating each slide:

  • It will pull the first heading on the page, whatever level that heading is, as the primary heading for the slide.
  • The script does not currently know what to do with internal links. If you need to include links to onwiki content, use external links instead.
    • VisualEditor may attempt to convert external links to Wikimedia projects into internal links automatically. There is no workaround for this other than fixing them in the source editor. Be sure to check that the links in your slide content are external (light blue) rather than internal (dark blue) links, or they won't work on the Dashboard.
  • It will ignore everything wrapped with <noinclude> tags, and will not display <translate> tags or <tvar>s. In this sense, it displays mostly how a regular, translatable page on Meta-Wiki would, with some key caveats that this documentation will attempt to cover.
  • The script will not be able to handle images or video directly. There are workarounds to this that are covered in the next section.



Right now, adding images to slides on the Dashboard is not as simple as simply adding the image in wikitext. Because the Dashboard is not hosted on a Wikimedia project, the usual method of referring to the file in question will not work.

The Dashboard will need a direct link to the image in order to parse it into valid HTML that will display on an external website. However, there is no way to make an HTML image (usually marked up with an <img> tag) display in both the Dashboard and onwiki.

In order to make it work on both, you will need to use the training module image template (Template:Training module image)

Here is an example of the template as it might be used in the slide content:

{{Training module image
| image = File:Example.jpg
| source =
| layout = alt-layout-40-right
| credit = An example image. Image: User:Mdd4696, public domain.

On wiki, this will be translated back into the usual way to embed images, using the image as the file and credit as the caption underneath. It'll look something like this:


On the dashboard, it will parse it to use source to embed the image, and layout to position it. alt-layout-40-right is just one of the available layout options; all the available CSS layouts are in the source code. The available layouts as of August 30 are:

Class name Image alignment Image size
alt-layout-50 centre 50%
alt-layout-30-right right 40%
alt-layout-30-left left 40%
alt-layout-30-right right 30%
alt-layout-30-left left 30%



Similarly to how the image template works, we have a video template: Template:Training module video. Here’s an example (see this in action):

{{Training module video
| video = File:Welcome & Purpose of the Dashboard (1 of 5).webm
| source =
| caption = Welcome & Purpose of the Dashboard (1 of 5)

The template includes three variables:

  • video - the video file to be embedded on the wiki, and which exists on either Wikimedia Commons or the local wiki.
  • caption- the caption used both on the wiki and on the dashboard.
  • source =a direct video link that gets embedded on the dashboard as an iframe. The easiest way to do this is to upload the video to YouTube and use their direct "embed" function. Note: On YouTube videos and some other source providers this link will not be the canonical link, but the "embed" version of this link (i.e. instead of



The Dashboard is able to render interactive components in these training modules. At present, the only method for this is with another template – Template:Training module quiz.

These quizzes are useful for quickly recapping sections, and to provide a way to break up long sections of text-heavy slides. Right now, it is not possible to store the user's input or to provide indepth feedback on their answers. It is recommended that this be done onwiki.

On the Dashboard, the quizzes take the form of a multiple-choice question with four answers. Users read the question or situation, then select which answer they think is correct or the most suitable. Upon clicking "Check Answer", the user will be shown a message explaining why the answer they selected is correct or incorrect.

The wikitext code for a quiz question looks like this:

{{Training module quiz
| question = Here is an example question
| correct_answer_id = 2
| answer_1 = The first answer, which is wrong
| explanation_1 = An explanation of why this answer is wrong
| answer_2 = The second answer, which is correct
| explanation_2 = An explanation of why this answer is correct
| answer_3 = The third answer, which is wrong
| explanation_3 = An explanation of why this answer is wrong
| answer_4 = The fourth answer, which is wrong
| explanation_4 = An explanation of why this answer is wrong

Everything here can be translated using the same method discussed in the next section.

The quizzes display very differently onwiki than on the Dashboard itself – this is because the Dashboard is not designed to directly replicate the onwiki content, but rather piece it together into its own slides. For an example of how this looks in both places, here is "Test Yourself: Image related abuse" from the Support and Safety training modules onwiki and on the Dashboard.



One of the major positives of using a setup like this is that translations can be automatically imported to the Dashboard from Meta-Wiki. Setting up a slide for translation uses virtually the same process as any other Meta-Wiki page (Extension:Translate). If you are unfamiliar with how to prepare pages for translation, refer to the guidelines for doing so on the Mediawiki wiki.

As a crash course:

  • Wrap the whole slide's text with translate tags;
  • Escape links with "tvar" tags; and
  • Mark things for translation, or have a translation administrator do so for you.

A correctly marked-for-translation page might look like this:

<noinclude><languages /></noinclude>


== Page title ==

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla arcu magna, tincidunt vitae commodo sed, [ tempus non ante].

Maecenas vel tortor vel neque semper tempus vitae ac felis. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos.


For slides including images or videos (or anything else that results in  close out any open <translate> tags in the main text and wrap only the text that needs to be translated – don't wrap the whole template with the tags, as it creates work for translators.

There are some differences when marking up pages for use on the Dashboard. The <languages /> tag, normally inserted at the top of a translatable page, will need to be wrapped in tags; otherwise the raw tag will display on the Dashboard.

Updating the dashboard


When you’re ready to see your changes, visit this link:

The module slug at the end of the URL should correspond to the module you are working on, like 'dealing-with-online-harassment-fundamentals'.

Doing this will force the dashboard to refresh and re-pull all content for the requested module. If it succeeds, it will display done!. If it doesn't succeed, you will instead be shown an error.

Slide organisation


If you have many slides or modules, it can be difficult to organise these in a cohesive way. There are a number of solutions to this problem depending on your usecase.

Onwiki index


The most simple way to organise slides is which an onwiki index, listing each slide with a link to the actual wikitext for each. The index for the Support and Safety training modules can be used as a reference for what this might look like. Notice the hierarchy here, which makes the modules easier to navigate through and consequently makes it easier to find the slide you need to change.

For the JSON files, it is recommended these are listed onwiki as well using a similar method. The Support and Safety training modules created multiple lists – for libraries, modules, and slides – linking to the JSON files for each for easy access.



When designing your modules, it may be advisable to create a spreadsheet, offwiki, in something like Microsoft Excel, LibreOffice, or Google Sheets. Doing this allows you to track, for each slide:

  • Slide ID number
  • Slide title / name
  • Slide slug
  • Module the slide is part of
  • Link to the slide's JSON
  • Link to the slide's content

You can also use functions to manipulate this table and make it easier to generate slugs. In Google Sheets, you can make use of functions like REGEXREPLACE() to help with this.



Categories can be useful to keep all of your slide content in one place for easier access and navigation. Wrap the categories you use for the slide pages on wiki with tags, like this:


This will allow you to keep the wiki pages organised onwiki, without altering the content of the slide on the dashboard. You can also make use of category sort keys, which allow the slides to be sorted in the category view. For example, the slide with the ID number 10204 might be categorised like this:


Questions and help


If you're struggling to put together a training module using the above documentation, feel free to message Joe Sutherland who is happy to help if he can.