+
+Let's say your format requires overriding the activity visibility badges as in the previous scenario example. Apart from the three main templates, the plugin must create several new template overrides until it reacher the activity badges one:
+
+CM item main file: format_pluginname/local/content/section/cmitem template:
+
+```handlebars
+{{! include the original course format template block }}
+{{< core_courseformat/local/content/section/cmitem }}
+ {{$ core_courseformat/local/content/cm }}
+ {{> format_pluginname/local/content/cm }}
+ {{/ core_courseformat/local/content/cm }}
+{{/ core_courseformat/local/content/section/cmitem }}
+```
+
+The content/cm template:
+
+```handlebars
+{{< core_courseformat/local/content/cm/activity }}
+ {{$ core_courseformat/local/content/cm/badges }}
+ {{> format_pluginname/local/content/cm/badges }}
+ {{/ core_courseformat/local/content/cm/badges }}
+{{/ core_courseformat/local/content/cm/activity }}
+```
+
+The content/cm/badges will contain only the overridden HTML.
+
+Apart from the templates files, the plugin could also provide overridden output classes to ensure that future versions will remain compatible if new ajax partials are required:
+
+In the example the extra output classes can look like:
+
+```php tile="format_pluginname\output\local\content\cm class"
+
+
+
+Benefits of this approach:
+
+- Easy to maintain in the long term. The code will remain the same if future versions require more main templates.
+- Overridden templates can be rendered as a regular course format output. Because each of the overridden mustaches has also its output class, the course format subsystem can render them independently.
+
+Negatives of this approach:
+
+- Requires extra files to keep the structure. Most of the files are just there to ensure the course format subsystem knows how to render them if needed in the future.
+
+#### Scenario 3: just keep a few renderer methods
+
+If your plugin is a completely different thing from a regular course you are most likely on your own. Your format may use a completely different set of renderer methods or output classes and you already have your own template structure.
+
+In that case, you may keep it that way. However, there are a few things you could add to your plugin in order to make it compatible with the new course output. Take in mind that the new course editor expects some conventions about renderer methods that should be easy to incorporate into your plugin.
+
+The first thing you should add is all the section and activities data attributes (see [course elements data attributes](#course-elements-data-attributes). The new course editor did not use CSS classes anymore but data attributes. If your format should be able to interact with the standard editor those attributes are necessary.
+
+Secondly, the new frontend JS modules use renderer methods to refresh a full section or an activity. If your format wants to keep this feature you should implement two methods on your renderer class:
+
+- **course_section_updated:** to render a single section.
+- **course_section_updated_cm_item:** to render a single course module item. Note that this method does not render an activity card only but also the full course item. In a regular course, this also includes the "li" element.
+
+And third, consider using "local/content" as your main course template, "output\local\content" as your main output class or, if you don't use output classes, use the render_content renderer method to print a full course. Those are the expected names to render the full course. For now, they are only used in your plugin "format.php" file but nobody can guarantee this will continue this way in the future.
+
+## The course editor structure
+
+The core_courseformat provides several JavaScript modules that will be enabled when a teacher edits the course. Those libraries use a reactive pattern to keep the course updated when some edit action is executed.
+
+The following diagram represents the data flow of the new architecture:
+
+![Course editor workflow](./_files/course_editor_workflow.png)
+
+### Enabling the course editor
+
+To enable the course editor in your format you should add the following method to your format base class (in your course/format/pluginname/lib.php):
+
+```php
+/**
+ * Enable the component based content.
+ */
+public function supports_components() {
+ return true;
+}
+```
+
+### Course elements data attributes.
+
+The course editor modules use data attributes to find the course elements in the page. If your plugin alters the default templates you should keep those attributes in your HTML structure.
+
+The following table describes the data attributes:
+
+| Concept | Required data attributes |
+|---------|------------------------|
+| **Section** | `data-for="section"`
`data-id={SECTION.ID}`
`data-number={SECTION.NUM}` |
+| **Section header** | `data-for="section_title"`
`data-id={SECTION.ID}
data-number={SECTION.NUM}` |
+| **Course module item (activity)** | `data-for="cmitem"`
`data-id={CM.ID}` |
+| **Course sections list** | `data-for="course_sectionlist"` |
+| **Section course modules list** | `data-for="cmlist"` |
+| **Course module action link** | `data-action={ACTIONNAME}`
`data-id={CM.ID}` |
+| **Section action link** | `data-action={ACTIONNAME}`
`data-id={SECTION.ID}` |
+| **Section info** | `data-for="sectioninfo"` |
diff --git a/versioned_docs/version-4.1/apis/plugintypes/format/migration.md b/versioned_docs/version-4.1/apis/plugintypes/format/migration.md
new file mode 100644
index 0000000000..2469a16131
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/format/migration.md
@@ -0,0 +1,284 @@
+---
+title: Migrating 3.11 formats
+tags:
+ - Plugins
+ - Format
+---
+
+
+
+
+
+
+import { getExample } from '@site/src/moodleBridge';
+
+The new course editor introduced n Moodle 4.0 reimplements most of the previous webservices, AMD modules, and internal logic of the course rendering. However, all formats since 3.11 will use the previous libraries by default until its final deprecation in Moodle 4.3. This document collects the main adaptations any 3.11 course format will require to continue working when this happens.
+
+## Changes summary
+
+The main areas affected by the new 4.0 course editor are:
+
+- Course format plugins are now part of the `core_courseformat` subsystem
+- The old format_base class is now `core_courseformat\base` and it is mandatory for all format plugins to extend.
+- Format plugin renderer is now mandatory (and in most cases they will extend `core_courseformat\output\section_renderer`)
+- The old format_section_renderer_base is now `core_courseformat\output\section_renderer`
+- The `core_courseformat\output\section_renderer` class now it extends core_course_renderer directly. This means that `$this->courserenderer` attribute is deprecated.
+- All renderer methods using html_writer are deprecated. All UI elements are now rendered using output classes and mustache files. Formats can provide alternative output classes and templates.
+- The new editor uses data attributes instead of CSS classes to locate section and activities elements in the page HTML. All elements must add those attributes to use the new AMD modules.
+- Most of the logic of the previous core_course/actions AMD module is now replaced with core_courseformat AMD modules, each one corresponding to the specific UI elements.
+- Formats can override the `core_courseformat\base::uses_course_index` in their base class to enable the course index.
+- Formats can override the `core_courseformat\base::supports_components` in their base class to use the new course editor library instead of the legacy one.
+- The course frontend uses a reactive state to maintain the UI elements updated. Format plugins can create new reactive AMD modules to interact with that state or extend the core_courseformat state classes to extend the data stored in that state.
+- Course formats now can implement the `core_courseformat\base::delete_format_data` hook to clean data when the course is deleted.
+- The course `format_base` class now provides a method `show_editor` to know if the user is editing or not the course depending on the page editing and the user capabilities. This method should be used instead of the previous `$PAGE->user_is_editing() && has_capability('moodle/course:manageactivities', $coursecontext)`. If you need to check for different capabilities, you can pass an array of them. If not specified, defaults to only `moodle:course/manageactivities`.
+
+## Moodle 3.11 vs 4.0 course editor architecture
+
+The 4.0 course editor follows a completely new pattern that is not compatible with the previous one. That new pattern is called **reactive components**.
+
+To ensure all 3.11 formats are still usable in 4.0 the new architecture is opt-in, meaning that in order to use the new libraries old formats must indicate to the system that they are compatible (overriding the `core_courseformat\base::supports_components`).
+
+The following table compares some of the main changes:
+
+| Moodle 3.11 | Moodle 4.0 |
+|---- | ---- |
+| AMD module "core_course/actions" is responsible for capturing the course edition actions, sending them to the correct course webservice, and replacing the returned HTML into the proper page elements. | Al the functionalities from the original actions are now divided into several AMD modules:
- core_courseformat/local/courseeditor: coordinates all the UI elements via a data structure called "reactive state data" (or simply, "state data").
- core_courseformat/local/courseeditor/mutations: centralizes all the backend calls and applies the results to the reactive state data before the UI components update the interface.
- core_courseformat/local/content/actions: captures the user clicks on specific action links and displays modals to get more information from the user if necessary (for example the destination position in a move activity action).
- core_courseformat/content/\*: ADM modules responsible for keeping some part of the UI aligned with the reactive state data.
- core_courseformat/courseeditor/\*: other modules and helpers
NOTE: some user actions like hiding and showing sections/activities are not yet migrated to the new architecture.
NOTE: updating a full section or activity HTML is still handled by the core_course/actions module. However, now both methods are public to the module and they are used by the new course editor.
|
+| course/dndupload.js file is responsible for handling any file dropping on the course page. | Moodle 4.0 still uses the course/dndupload.js to handle files dropped into the course area. |
+| The webservice core_course_edit_section is responsible for updating a course section and returning the section header and the activities list HTML. |
Except for showing and hiding a section (not migrated yet) the rest of the section actions are now handled by the new `core_courseformat_update_course` webservice.
The new webservice has the same parameters for both section and activity actions and always returns a standardized data structure to interact with the frontend reactive state data. This means that it does not return HTML fragments anymore.
|
+| The webservice core_course_edit_module is responsible for updating activity and returning the activity HTML or other page fragments. |
Except for showing and hiding an activity (not migrated yet) the rest of the activity actions are now handled by the new `core_courseformat_update_course` webservice.
The new webservice has the same parameters for both section and activity actions and always returns a standardized data structure to interact with the frontend reactive state data. This means that it does not return HTML fragments anymore.
|
+| All frontend JS logic is responsible for interacting with the backend and updating all the necessary frontend elements depending on the return value. |
The JS logic is now distributed into several modules called "components". Each module can only interact with a specific page element and watch a data structure called reactive state date (or simply "state data").
The main points of the new component structure are:
- The initial state data is loaded using the `core_courseformat_get_state` webservice
- All components are registered into the core_courseformat/courseeditor page instance.
- When the state data changes, the course editor instance triggers the component's watchers methods to update the UI.
- Components are not able to alter the state data. If a component captures an action that requires some state change, it asks the course editor to perform a state mutation.
|
+| Formats can alter the page HTML by overriding format_section_renderer_base methods |
Most renderer methods are now deprecated and have been migrated to output classes and mustache templates. There are only a few rendered methods formats that can override.
Now format plugins can override output classes by simply creating the equivalent format_pluginname/output/courseformat/* class. For example, core_courseformat\output\local\content can be overridden by creating a format_pluginname\output\courseformat\content class.
Important note: the new mustache structure uses partials and blocks to include sub-templates. This opens the door to a future frontend course rendering but it also makes the template overriding a bit more complex. See the "overriding templates" section for more information.
|
+|
Format renderer is optional. If none is provided the course format renderer_base is used.
Inside a format rendered the `$this->courserenderer` attribute is used to access the course renderer methods.
| Format renderer is mandatory. The base core_courseformat\output\section_renderer now extends the core_course_renderer class and `$this->courserenderer` is deprecated. |
+| The page elements are located using css class names such as "li.activity", ".actions", or "li.section". | All page elements are now located using data attributes. See [Course elements data attributes](./index.md#course-elements-data-attributes) for more information. |
+| The course is rendered using print_single_section_page or print_multiple_section_page depending on the number of sections to render. |
The course format base instance contains all the necessary data to determine the way a course is rendered. To Specify a single section page formats should use `$format->set_section_number` method before rendering the course.
Once the format instance setup is finished, the course is rendered using the `content` output class. See migrating old renderer methods to outputs section for more information.
|
+| To know if the user is editing the course, the format should check for `$PAGE->user_is_editing()` to know if edit is enabled and also `has_capability('moodle/course:update', $coursecontext)` to know if the user has the required capabilities. | The format base class have a method `$format->show_editor()` that do all the user and page validations to know if the current course display has to include editor options or not. |
+
+The following diagram represents the data flow of the new architecture:
+
+![Course editor workflow](./_files/course_editor_workflow.png)
+
+## First steps to migrate a 3.11 course format to 4.0
+
+From 4.0 the course/format folder has its own subsystem called core_courseformat. This subsystem contains all the course rendering logic (only some minor elements are still in the original location for retro compatibility until Moodle 4.3).
+
+To ensure your format plugin is integrated with the new subsystem:
+
+- The main format_pluginname class should extend `core_courseformat\base` instead of the old format_base one.
+- Your plugin **must provide a renderer class**. In most cases this class **will extend `core_courseformat\output\section_renderer`**.
+- Any output class your plugin needs to override should be located in format_pluginname/classes/output/courseformat
+
+In summary, the first two things you need to adapt to your format are:
+
+### Point 1: create a renderer class
+
+Now renderer classes are mandatory for course format plugins. Here there are two scenarios:
+
+Scenario 1: if you plugin already has one you should replace the old "extends format_section_renderer_base" by "extends core_courseformat\output\section_renderer".
+
+Scenario 2: If your plugin does not have a renderer, create a file **course/format/pluginname/classes/output/renderer.php** with a content like:
+
+
+ View example
+
+
+import Renderer from '!!raw-loader!./_examples/output/renderer.php';
+const RendererProps = {
+ examplePurpose: 'Output renderer',
+ plugintype: 'format',
+ pluginname: 'pluginname',
+ filepath: '/output/renderer.php',
+};
+
+
{getExample(RendererProps, Renderer)}
+
+
+
+
+### Point 2: fix your base class
+
+All Moodle 3.11 formats have a base format class extending format_base class from core_course. In Moodle 4.0 this class has been moved to `core_courseformat\base`. This means that you should replace the existing extends to avoid the deprecation message.
+
+For compatibility reasons, the base class does not use a namespace and should be located in your plugin "lib.php" file. This could change after Moodle 4.3 when most old course rendering methods will be removed from core.
+
+## The new output architecture
+
+When the debug messages are enabled, all 3.11 format plugins will show several deprecation messages. Most of them are due to the fact that almost all previous renderer methods are now deprecated. The full list can be found in the **course/upgrade.txt** file.
+
+Until 3.11 all course page elements are rendered using html_writer inside renderer methods. This made the UI hard to maintain because most of the methods are referring to the standard course structure (section_right_content, section_left_content, start_section_list, end_section_list…) instead of generic concepts like sections, activities, or activity menu.
+
+With the new architecture, almost all UI elements are rendered using:
+
+- An **output class** that generates the data to render. For example, course/format/classes/output/local/content/section.php
+- A **mustache template** to render output class data. For example, course/format/templates/local/content/section.mustache
+- An optional **reactive component** to update the frontend when the reactive state data changes: For example, course/format/amd/src/local/content/section.js
+
+The following diagram represents the new output structure compared to the 3.11 one:
+
+![Output classes structure](./_files/course_format_output.png)
+
+## Migrating old renderer methods to outputs
+
+The process of migrating a renderer method to output can be complex depending on the element your format overrides. For these reasons, Moodle 3.11 formats will remain using the old renderer methods until they explicitly use the new outputs.
+
+### Step 1: start using output components and renderers
+
+As in Moodle 3.11 formats, all the course view is initialized and rendered in the "course/format/pluginname/format.php" file. However, the way the outputs are initialized is quite different from the previous version.
+
+In Moodle 3.11 the format.php process was something like:
+
+1. Do some param validations
+2. Get the course format instance using `course_get_format` or `core_courseformat\base::instance`
+3. Get the format/course renderer using: `$PAGE->get_renderer('format_pluginname')`;
+4. Use the renderer `print_single_section_page` or `print_multiple_section_page` depending on the section param.
+
+The problems with that approach were:
+
+- There are two main renderer methods which are almost the same
+- The auxiliary renderer methods require a big amount of params even if they are not needed for the method because they need to provide those parameters to all the child methods.
+
+To avoid this situation now the format base class instance is used as a single exchange param to all output classes. Once the format instance is initialized every output class can get all necessary information from it.
+
+The new workflow in 4.0 is:
+
+
+ View example
+
+
+import Format from '!!raw-loader!./_examples/format.php';
+const FormatProps = {
+ examplePurpose: 'Format course display',
+ plugintype: 'format',
+ pluginname: 'pluginname',
+ filepath: '/format.php',
+};
+
+
{getExample(FormatProps, Format)}
+
+
+
+
+Some important notes about the code:
+
+- The rendered class now can be obtained using `$format->get_renderer`
+- Format plugins can override any core_courseformat output class (see sections below for more details). To get the correct output you need to use `$format->get_output_classname` method.
+- As you may notice, the output class is rendered directly using the render method, not the `render_from_template` one. This is possible because all output classes implement the new Moodle 4.0 `named_templatable` interface.
+
+### Step 2: override any output class to alter the template data to your plugin needs
+
+Instead of having several renderer methods on a single file, the core_courseformat subsystem splits the output logic through several small classes, each one for a specific UI component. Format plugins can easily override specific classes to alter the template data.
+
+The course format base class has a special method called get_output_classname that returns the overridden class name if available in the format plugin, or the core one if not. In order to detect the format classes, your plugin must place the overridden one in your format_pluginname\output\courseformat\...
+
+For example, if a format plugin wants to add new options to the section action menu it should override the core_courseformat\output\local\content\section\controlmenu. To do so the plugin class should be format_topics\output\courseformat\content\section\controlmenu. You can find an example of an overridden output in the "course/format/topics/classes/output/courseformat/content/section/controlmenu.php" file.
+
+### Step 3: create the basic mustache structure
+
+Unlike output classes, mustache files cannot be extended nor overridden. To be able to alter specific mustaches your plugin must provide a minimum template structure. Furthermore, your plugin must provide some overridden output classes providing the alternative mustache templates location.
+
+In moodle 3.11 the course render uses html_writer to generate the course view, where each renderer method has both data collection and HTML generating inside. This is not the case in Moodle 4.0. From now on, the full output data is collected via output classes before rendering all the nested mustache templates.
+
+The course format subsystem requires a minimum of 3 mustaches to render a course:
+
+- **local/content**: the full course template
+- **local/content/section**: a section template. Used to refresh a section via ajax
+- **local/content/section/cmitem**: an activity item template: Used to refresh an activity via ajax
+
+The first thing your plugin needs is to create that structure and link it to the output components. Follow the guide on the [create format plugin page](./index.md#creating-the-basic-output-structure) to know how to create the basic structure.
+
+### Step 4: create your own custom mustache blocks
+
+Once your plugin has the basic mustache structure, you can provide extra mustache blocks to override parts of the page. Follow the [Override mustache blocks](./index.md#override-mustache-blocks) on the Creating a course format page to know how to do it.
+
+## Enabling course index in your format
+
+If your course format plugin uses a sections-activity structure it is possible to enable the course index. Add the course index in your format is as easy as overriding a method on your format base class:
+
+
+ View example
+
+
+import BaseCourseIndex from '!!raw-loader!./_examples/lib_course_index.php';
+const BaseCourseIndexProps = {
+ examplePurpose: 'Format base class with course index enabled',
+ plugintype: 'format',
+ pluginname: 'pluginname',
+ filepath: '/lib.php',
+};
+
+
{getExample(BaseCourseIndexProps, BaseCourseIndex)}
+
+
+
+
+It is important to note that the course index drawer is only available in Boost based themes, Classic based themes won't display it.
+
+See the course index section in the create format plugin page for more information.
+
+## Enabling reactive components
+
+Moodle 4.0 introduced a new reactive course editor for the frontend. However, the new modules are not compatible with the previous YUI ones. To prevent errors in the 3.11 formats the new libraries are opt-in, meaning plugins must adapt their code before using it.
+
+Step 1: add data attributes to the HTML elements
+The previous YUI editor uses CSS classes to identify sections, activities, and section headers. Nowadays, the use of CSS classes beyond styling is discouraged so the new library uses data attributes to identify the main course page elements.
+
+To adapt your plugin to the new editor you must add the proper data attributes. The following table explains the new selectors:
+
+| Concept | 3.11 equivalent | 4.0 data attributes |
+| ---- | ---- | ---- |
+| Section | `li.section#section-{SECTION.NUM}` | `data-for="section"`
`data-id={SECTION.ID}`
`data-number={SECTION.NUM}` |
+| Section header | `#sectionid-{SECTION.ID}-title` | `data-for="section_title"`
`data-id={SECTION.ID}`
`data-number={SECTION.NUM}` |
+| Course module item (activity) | `li.activity#module-{CM.ID}` | `data-for="cmitem"`
`data-id={CM.ID}` |
+| Course sections list | `.course-content>ul` | `data-for="course_sectionlist"`
| `Section course modules list | Li.section .content .section` | `data-for="cmlist"`
|
+| Course module action link | `a.cm-edit-action` | `data-action={ACTIONNAME}`
`data-id={CM.ID}` |
+| Section action link | `.section_action_menu` | `data-action={ACTIONNAME}`
`data-id={SECTION.ID}`
+| Section info | `.section_availability` | `data-for="sectioninfo"` |
+
+### Step 2: enable supports components feature
+
+Once your plugin has all the necessary data attributes you can disable the old YUI editor and enable the new reactive one by adding this method to your plugin base class:
+
+
+ View example
+
+
+import BaseComponents from '!!raw-loader!./_examples/lib_components.php';
+const BaseComponentsProps = {
+ examplePurpose: 'Format base class with components enabled',
+ plugintype: 'format',
+ pluginname: 'pluginname',
+ filepath: '/lib.php',
+};
+
+
{getExample(BaseComponentsProps, BaseComponents)}
+
+
+
+
+### Step 3: check the reactive components are enabled.
+
+In principle, if you create the basic mustache structure as described in the previous chapter the course editor should work as expected. However, to check if they are working properly:
+
+1. Enable developer debug level on your site and access a course as an administrator
+2. Wait for the page to load and find in the debug footer the "Reactive instances" section.
+3. Click on the button "CourseEditorXXXX" (where XXXX is the current course ID)
+4. Once the panel opens, click on the "Highlight OFF" button (it will change to "Highlight ON")
+5. Go to the top of the page and check the course content has several thick blue borders.
+
+If the border appears around all the course content elements (sections, section headers and activities) means that the course editor has registered all the course content as a reactive component.
+
+If you don't have a "CourseEditorXXXX" button or the content elements don't get highlighted means that, most probably, you override the main content mustache in a peculiar way and removed the JS initialization.
+
+To re-introduce the JS initialization you should edit the plugin's "content.mustache" file with the following:
+
+- Add `id="{{uniqid}}-course-format"` to the course content div element.
+- At the end of the template add:
+
+```handlebars
+{{#js}}
+require(['core_courseformat/local/content'], function(component) {
+ component.init('{{uniqid}}-course-format', {}, {{sectionreturn}});
+});
+{{/js}}
+```
+
+By doing that the content main reactive component should be initialized and if you enable the highlighting the content should have a blue border. If some if the inner elements does not have a blue border when highlight is ON means that some data attribute is missing. Check the step 1 of this chapter for more information.
diff --git a/versioned_docs/version-4.1/apis/plugintypes/index.md b/versioned_docs/version-4.1/apis/plugintypes/index.md
new file mode 100644
index 0000000000..16b5b828b8
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/index.md
@@ -0,0 +1,142 @@
+---
+title: Plugin types
+tags:
+ - Plugins
+ - core
+ - API
+---
+
+Moodle is a powerful, and very extensible, Learning Management System. One of its core tenets is its extensibility, and this is primarily achieved through the development of plugins.
+
+A wider range of plugin types are available and these should be selected depending on your needs.
+
+## Things you can find in all plugins
+
+Although there are many different types of plugin, there are some things that work the same way in all plugin types. Please see the [Plugin files](./commonfiles) documentation that describes common files which are found in many plugin types.
+
+## Naming conventions
+
+Plugins typically have at least two names:
+
+- The friendly name, shown to users, and
+- A machine name used internally.
+
+The machine name must meet the following rules:
+
+- It must start with a lowercase latin letter
+- It may contain only lowercase latin letters, numbers, and underscores
+- It must end with a lowercase latin letter, or a number
+- The hyphen, and minus character `-` are not allowed
+
+If a plugin does not meet these requirements then it will be silently ignored.
+
+:::tip
+
+Plugin name validation takes place in `core_component::is_valid_plugin_name()` and the following regular expression is used:
+
+```
+/^[a-z](?:[a-z0-9_](?!__))*[](a-z0-9)+$/
+```
+
+:::
+
+:::danger Activity module exception
+
+The underscore character is not supported in activity modules for legacy reasons.
+
+:::
+
+
+
+| Plugin type | Component name ([Frankenstyle](/general/development/policies/codingstyle/frankenstyle)) | Moodle path | Description | Moodle versions |
+| --- | --- | --- | --- | --- |
+| [Activity modules](./mod/index.mdx) | mod | /mod | Activity modules are essential types of plugins in Moodle as they provide activities in courses. For example: Forum, Quiz and Assignment. | 1.0+ |
+| [Antivirus plugins](./antivirus/index.mdx) | antivirus | /lib/antivirus | Antivirus scanner plugins provide functionality for virus scanning user uploaded files using third-party virus scanning tools in Moodle. For example: ClamAV. | 3.1+ |
+| [Assignment submission plugins](./assign/submission.md) | assignsubmission | /mod/assign/submission | Different forms of assignment submissions | 2.3+ |
+| [Assignment feedback plugins](./assign/feedback.md) | assignfeedback | /mod/assign/feedback | Different forms of assignment feedbacks | 2.3+ |
+| [Book tools](./mod_book/index.md) | booktool | /mod/book/tool | Small information-displays or tools that can be moved around pages | 2.1+ |
+| [Course Custom fields](./customfield/index.md) | customfield | /customfield/field | Custom field types, used in Custom course fields | 3.7+ |
+| [Database fields](./mod_data/fields.md) | datafield | /mod/data/field | Different types of data that may be added to the Database activity module | 1.6+ |
+| [Database presets](./mod_data/presets.md) | datapreset | /mod/data/preset | Pre-defined templates for the Database activity module | 1.6+ |
+| [LTI sources](https://docs.moodle.org/dev/External_tool_source) | ltisource | /mod/lti/source | LTI providers can be added to external tools easily through the external tools interface see [Documentation on External Tools](https://docs.moodle.org/en/External_tool). This type of plugin is specific to LTI providers that need a plugin that can register custom handlers to process LTI messages | 2.7+ |
+| [File Converters](./fileconverter/index.md) | fileconverter | /files/converter | Allow conversion between different types of user-submitted file. For example from .doc to PDF. | 3.2+ |
+| [LTI services](https://docs.moodle.org/dev/LTI_services) | ltiservice | /mod/lti/service | Allows the implementation of LTI services as described by the IMS LTI specification | 2.8+ |
+| [Machine learning backends](./mlbackend/index.md) | mlbackend | /lib/mlbackend | Prediction processors for analytics API | 3.4+ |
+| [Forum reports](./mod_forum/index.md) | forumreport | /mod/forum/report | Display various reports in the forum activity | 3.8+ |
+| [Quiz reports](https://docs.moodle.org/dev/Quiz_reports) | quiz | /mod/quiz/report | Display and analyse the results of quizzes, or just plug miscellaneous behaviour into the quiz module | 1.1+ |
+| [Quiz access rules](https://docs.moodle.org/dev/Quiz_access_rules) | quizaccess | /mod/quiz/accessrule | Add conditions to when or where quizzes can be attempted, for example only from some IP addresses, or student must enter a password first | 2.2+ |
+| [SCORM reports](https://docs.moodle.org/dev/SCORM_reports) | scormreport | /mod/scorm/report | Analysis of SCORM attempts | 2.2+ |
+| [Workshop grading strategies](https://docs.moodle.org/dev/Workshop_grading_strategies) | workshopform | /mod/workshop/form | Define the type of the grading form and implement the calculation of the grade for submission in the [Workshop](https://docs.moodle.org/dev/Workshop) module | 2.0+ |
+| [Workshop allocation methods](https://docs.moodle.org/dev/Workshop_allocation_methods) | workshopallocation | /mod/workshop/allocation | Define ways how submissions are assigned for assessment in the [Workshop](https://docs.moodle.org/dev/Workshop) module | 2.0+ |
+| [Workshop evaluation methods](https://docs.moodle.org/dev/Workshop_evaluation_methods) | workshopeval | /mod/workshop/eval | Implement the calculation of the grade for assessment (grading grade) in the [Workshop](https://docs.moodle.org/dev/Workshop) module | 2.0+ |
+| [Blocks](./blocks/index.md) | block | /blocks | Small information-displays or tools that can be moved around pages | 2.0+ |
+| [Question types](https://docs.moodle.org/dev/Question_types) | qtype | /question/type | Different types of question (for example multiple-choice, drag-and-drop) that can be used in quizzes and other activities | 1.6+ |
+| [Question behaviours](https://docs.moodle.org/dev/Question_behaviours) | qbehaviour | /question/behaviour | Control how student interact with questions during an attempt | 2.1+ |
+| [Question import/export formats](https://docs.moodle.org/dev/Question_formats) | qformat | /question/format | Import and export question definitions to/from the question bank | 1.6+ |
+| [Text filters](./filter/index.md) | filter | /filter | Automatically convert, highlight, and transmogrify text posted into Moodle. | 1.4+ |
+| [Editors](https://docs.moodle.org/dev/Editors) | editor | /lib/editor | Alternative text editors for editing content | 2.0+ |
+| [Atto editor plugins](https://docs.moodle.org/dev/Atto) | atto | /lib/editor/atto/plugins | Extra functionality for the Atto text editor | 2.7+ |
+| [TinyMCE editor plugins](./tiny/legacy.md) | tinymce | /lib/editor/tinymce/plugins | Extra functionality for the TinyMCE text editor. | 2.4+ |
+| [Enrolment plugins](./enrol/index.md) | enrol | /enrol | Ways to control who is enrolled in courses | 2.0+ |
+| [Authentication plugins](https://docs.moodle.org/dev/Authentication_plugins) | auth | /auth | Allows connection to external sources of authentication | 2.0+ |
+| [Admin tools](https://docs.moodle.org/dev/Admin_tools) | tool | /admin/tool | Provides utility scripts useful for various site administration and maintenance tasks | 2.2+ |
+| [Log stores](./logstore/index.md) | logstore | /admin/tool/log/store | Event logs storage back-ends | 2.7+ |
+| [Availability conditions](./availability/index.md) | availability | /availability/condition | Conditions to restrict user access to activities and sections. | 2.7+ |
+| [Calendar types](https://docs.moodle.org/dev/Calendar_types) | calendartype | /calendar/type | Defines how dates are displayed throughout Moodle | 2.6+ |
+| [Messaging consumers](https://docs.moodle.org/dev/Messaging_consumers) | message | /message/output | Represent various targets where messages and notifications can be sent to (email, sms, jabber, ...) | 2.0+ |
+| [Course formats](./format/index.md) | format | /course/format | Different ways of laying out the activities and blocks in a course | 1.3+ |
+| [Data formats](https://docs.moodle.org/dev/Data_formats) | dataformat | /dataformat | Formats for data exporting and downloading | 3.1+ |
+| [User profile fields](https://docs.moodle.org/dev/User_profile_fields) | profilefield | /user/profile/field | Add new types of data to user profiles | 1.9+ |
+| [Reports](https://docs.moodle.org/dev/Reports) | report | /report | Provides useful views of data in a Moodle site for admins and teachers | 2.2+ |
+| [Course reports](https://docs.moodle.org/dev/Course_reports) | coursereport | /course/report | Reports of activity within the course | Up to 2.1 (for 2.2+ see [Reports](https://docs.moodle.org/dev/Reports)) |
+| [Gradebook export](https://docs.moodle.org/dev/Gradebook_export) | gradeexport | /grade/export | Export grades in various formats | 1.9+ |
+| [Gradebook import](https://docs.moodle.org/dev/Gradebook_import) | gradeimport | /grade/import | Import grades in various formats | 1.9+ |
+| [Gradebook reports](https://docs.moodle.org/dev/Gradebook_reports) | gradereport | /grade/report | Display/edit grades in various layouts and reports | 1.9+ |
+| [Advanced grading methods](https://docs.moodle.org/dev/Grading_methods) | gradingform | /grade/grading/form | Interfaces for actually performing grading in activity modules (for example Rubrics) | 2.2+ |
+| [MNet services](https://docs.moodle.org/dev/MNet_services) | mnetservice | /mnet/service | Allows to implement remote services for the [MNet](https://docs.moodle.org/dev/MNet) environment (deprecated, use web services instead) | 2.0+ |
+| [Webservice protocols](https://docs.moodle.org/dev/Webservice_protocols) | webservice | /webservice | Define new protocols for web service communication (such as SOAP, XML-RPC, JSON, REST ...) | 2.0+ |
+| [Repository plugins](./repository/index.md) | repository | /repository | Connect to external sources of files to use in Moodle | 2.0+ |
+| [Portfolio plugins](https://docs.moodle.org/dev/Portfolio_plugins) | portfolio | /portfolio | Connect external portfolio services as destinations for users to store Moodle content | 1.9+ |
+| [Search engines](https://docs.moodle.org/dev/Search_engines) | search | /search/engine | Search engine backends to index Moodle's contents. | 3.1+ |
+| [Media players](https://docs.moodle.org/dev/Media_players) | media | /media/player | Pluggable media players | 3.2+ |
+| [Plagiarism plugins](https://docs.moodle.org/dev/Plagiarism_plugins) | plagiarism | /plagiarism | Define external services to process submitted files and content | 2.0+ |
+| [Cache store](https://docs.moodle.org/dev/Cache_store) | cachestore | /cache/stores | Cache storage back-ends. | 2.4+ |
+| [Cache locks](https://docs.moodle.org/dev/Cache_locks) | cachelock | /cache/locks | Cache lock implementations. | 2.4+ |
+| [Themes](https://docs.moodle.org/dev/Themes) | theme | /theme | Change the look of Moodle by changing the the HTML and the CSS. | 2.0+ |
+| [Local plugins](./local/index.mdx) | local | /local | Generic plugins for local customisations | 2.0+ |
+| [Content bank content types](https://docs.moodle.org/dev/Content_bank_content_types) | contenttype | /contentbank/contenttype | Content types to upload, create or edit in the content bank and use all over the Moodle site | 3.9+ |
+| [H5P libraries](https://docs.moodle.org/dev/H5P_libraries) | h5plib | /h5p/h5plib | Plugin type for the particular versions of the H5P integration library. | 3.9+ |
+| [Question bank plugins](./qbank/index.md) | qbank | /question/bank | Plugin type for extending question bank functionality. | 4.0+ |
+
+
+ Obtaining the list of plugin types known to your Moodle
+
+You can get an exact list of valid plugin types for your Moodle version using the following example:
+
+```php title="/plugintypes.php"
+get_plugin_types() as $type => $dir) {
+ $dir = substr($dir, strlen($CFG->dirroot));
+ printf(
+ "%-20s %-50s %s" . PHP_EOL,
+ $type,
+ $pluginman->plugintype_name_plural($type),
+ $dir)
+ ;
+}
+```
+
+
+
+## See also
+
+- [Guidelines for contributing code](https://docs.moodle.org/dev/Guidelines_for_contributed_code)
+- [Core APIs](../../apis.md)
+- [Frankenstyle](/general/development/policies/codingstyle/frankenstyle)
+- [Moodle Plugins directory](http://moodle.org/plugins)
+- [Tutorial](https://docs.moodle.org/dev/Tutorial) to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.
diff --git a/versioned_docs/version-4.1/apis/plugintypes/local/index.mdx b/versioned_docs/version-4.1/apis/plugintypes/local/index.mdx
new file mode 100644
index 0000000000..403785d5f8
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/local/index.mdx
@@ -0,0 +1,152 @@
+---
+title: Local plugins
+tags:
+ - Plugins
+---
+
+import {
+ getExample,
+ getFileNameWithComponentPath,
+ CodeBlock,
+} from '@site/src/moodleBridge';
+
+import {
+ Lib,
+ SettingsPHP,
+} from '../../_files';
+
+The recommended way to add new functionality to Moodle is to create a new standard plugin (for example, activity, block, authentication, enrol). The `local` plugin-type is mostly suitable for things that do not fit into these standard plugin types.
+
+Local plugins are used in cases when no standard plugin is suitable. Examples of these situations include:
+
+- event consumers communicating with external systems
+- custom definitions of web services and external functions
+- applications that extend moodle at the system level (for example hub server, amos server)
+- custom admin settings
+- extending the navigation block with custom menus
+- new database tables used in core hacks (**strongly discouraged**)
+- new capability definitions used in core hacks (**strongly discouraged**)
+
+## List of differences from normal plugins:
+
+Local plugins have several important differences from the standard plugin types, including:
+
+- they are always executed last during install, and upgrade. This is guaranteed by their order in `get_plugin_types()`.
+- they are _expected_ to use event handlers. Event subscriptions are intended for communication from core to plugins only, making local plugins the ideal candidate for them.
+- they can add admin settings to any settings page. They are loaded last when constructing admin tree to enable this.
+- they _do not need_ to have any UI. Other plugin types are usually visible somewhere within the interface.
+
+## File structure
+
+Local plugins support the [standard plugin files](../commonfiles) supported by other plugin types.
+
+## Examples
+
+The following examples show some ways in which you can use a local plugin.
+
+### Adding an element to the settings menu
+
+A local plugin can extend or modify the settings navigation by defining a function named `local_[pluginname]_extend_settings_navigation` in its `lib.php`. This is called when Moodle builds the settings block. For example:
+
+export const settingsNavigationExample = `
+function local_[pluginname]_extend_settings_navigation($settingsnav, $context) {
+ global $CFG, $PAGE;\n
+\
+ // Only add this settings item on non-site course pages.
+ if (!$PAGE->course or $PAGE->course->id == 1) {
+ return;
+ }\n
+\
+ // Only let users with the appropriate capability see this settings item.
+ if (!has_capability('moodle/backup:backupcourse', context_course::instance($PAGE->course->id))) {
+ return;
+ }\n
+\
+ if ($settingnode = $settingsnav->find('courseadmin', navigation_node::TYPE_COURSE)) {
+ $strfoo = get_string('foo', 'local_[pluginname]');
+ $url = new moodle_url('/local/[pluginname]/foo.php', array('id' => $PAGE->course->id));
+ $foonode = navigation_node::create(
+ $strfoo,
+ $url,
+ navigation_node::NODETYPE_LEAF,
+ '[pluginname]',
+ '[pluginname]',
+ new pix_icon('t/addcontact', $strfoo)
+ );
+ if ($PAGE->url->compare($url, URL_MATCH_BASE)) {
+ $foonode->make_active();
+ }
+ $settingnode->add_node($foonode);
+ }
+}
+`;
+
+
+
+### Removing the "Site Home" link from the navigation menu
+
+A plugin can modify existing navigation, and settings navigation, components from within the `local_[pluginname]_extend_navigation()` function, for example:
+
+export const modifyNavigationExample = `
+function local_[pluginname]_extend_navigation(global_navigation $navigation) {
+ if ($home = $navigation->find('home', global_navigation::TYPE_SETTING)) {
+ $home->remove();
+ }
+}
+`;
+
+
+
+### Adding Site Wide Settings For Your Local Plugin
+
+export const siteWideSettingsExample = `
+// Ensure the configurations for this site are set
+if ($hassiteconfig) {\n
+\
+ // Create the new settings page
+ // - in a local plugin this is not defined as standard, so normal $settings->methods will throw an error as
+ // $settings will be null
+ $settings = new admin_settingpage('local_[pluginname]', 'Your Settings Page Title');\n
+\
+ // Create
+ $ADMIN->add('localplugins', $settings);\n
+\
+ // Add a setting field to the settings for this page
+ $settings->add(new admin_setting_configtext(
+ // This is the reference you will use to your configuration
+ 'local_[pluginname]/apikey',\n
+\
+ // This is the friendly title for the config, which will be displayed
+ 'External API: Key',\n
+\
+ // This is helper text for this config field
+ 'This is the key used to access the External API',\n
+\
+ // This is the default value
+ 'No Key Defined',\n
+\
+ // This is the type of Parameter this config is
+ PARAM_TEXT
+ ));
+}
+`;
+
+
diff --git a/versioned_docs/version-4.1/apis/plugintypes/logstore/index.md b/versioned_docs/version-4.1/apis/plugintypes/logstore/index.md
new file mode 100644
index 0000000000..3449ea77ac
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/logstore/index.md
@@ -0,0 +1,14 @@
+---
+title: Logstore plugins
+tags:
+ - Logging
+ - Events
+ - logstore
+ - Plugin
+ - Plugintype
+documentationDraft: true
+---
+
+Moodle supports the ability to define a custom log storage system using the `logstore` plugin type. This hasn't been documented yet - perhaps you are able to help us.
+
+
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mlbackend/index.md b/versioned_docs/version-4.1/apis/plugintypes/mlbackend/index.md
new file mode 100644
index 0000000000..27de3c670a
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mlbackend/index.md
@@ -0,0 +1,212 @@
+---
+title: Machine learning backends
+tags:
+ - Analytics
+ - API
+ - plugintype
+---
+
+
+
+
+Machine learning backends process the datasets generated from the indicators and targets calculated by the [Analytics API](../../subsystems/analytics/index.md). They are used for machine learning training, prediction and models evaluation.
+
+:::tip
+
+We strongly recommend that you read the [Analytics API](../../subsystems/analytics/index.md) documentation to help understand the core concepts, how they are implemented in Moodle, and how machine learning backend plugins fit into the analytics API.
+
+:::
+
+The communication between machine learning backends and Moodle is through files because the code that will process the dataset can be written in PHP, in Python, in other languages or even use cloud services. This needs to be scalable so they are expected to be able to manage big files and train algorithms reading input files in batches if necessary.
+
+## Backends included in Moodle core
+
+### PHP
+
+The **PHP backend** is the default predictions processor as it is written in PHP and does not have any external dependencies. It is using logistic regression.
+
+### Python
+
+The **Python backend** requires *python* binary (either python 2 or python 3) and [moodlemlbackend python package](https://pypi.python.org/pypi?name=moodlemlbackend&version=0.0.5&:action=display) which is maintained by Moodle HQ.
+
+The Python version and libraries versions used are **very important**. We recommend using Python 3.7 for mlbackend 3.x versions.
+
+The Python backend is based on [Google's tensorflow library](https://www.tensorflow.org/) and uses a feed-forward neural network with 1 single hidden layer.
+
+The *moodlemlbackend* package does store model performance information that can be visualised using [tensorboard](https://www.tensorflow.org/get_started/summaries_and_tensorboard). Information generated during models evaluation is available through the models management page, under each model *Actions > Log* menu.
+
+:::tip
+
+We recommend use of the **Python** backend as it is able to predict more accurately than the PHP backend and it is faster.
+
+:::
+
+:::info
+
+You can [view the source](https://github.com/moodlehq/moodle-mlbackend-python) of the _moodlemlbackend_ library that Moodle uses.
+
+:::
+
+## File structure
+
+Machine learning backends are located in the `lib/mlbackend` directory.
+
+Each plugin is in a separate subdirectory and consists of a number of _mandatory files_ and any other files the developer is going to use.
+
+
+ View an example directory layout for the `mlbackend_python` plugin.
+
+```console
+lib/mlbackend/python
+├── classes
+│ ├── privacy
+│ │ └── provider.php
+│ └── processor.php
+├── lang
+│ └── en
+│ └── mlbackend_python.php
+├── phpunit.xml
+├── settings.php
+├── tests
+│ └── processor_test.php
+├── upgrade.txt
+└── version.php
+```
+
+
+
+Some of the important files for the mlbackend plugintype are described below. See the [common plugin files](../commonfiles) documentation for details of other files which may be useful in your plugin.
+
+## Interfaces
+
+A summary of these interfaces purpose:
+
+- Evaluate a provided prediction model
+- Train machine learning algorithms with the existing site data
+- Predict targets based on previously trained algorithms
+
+### Predictor
+
+This is the basic interface to be implemented by machine learning backends. Two main types are, *classifiers* and *regressors*. We provide the *Regressor* interface but it is not currently implemented by core Machine learning backends. Both of these are supervised algorithms. Each type includes methods to train, predict and evaluate datasets.
+
+You can use **is_ready** to check that the backend is available.
+
+```php
+/**
+ * Is it ready to predict?
+ *
+ * @return bool
+ */
+public function is_ready();
+```
+
+**clear_model** and **delete_output_dir** purpose is to clean up stuff created by the machine learning backend.
+
+```php
+/**
+ * Delete all stored information of the current model id.
+ *
+ * This method is called when there are important changes to a model,
+ * all previous training algorithms using that version of the model
+ * should be deleted.
+ *
+ * @param string $uniqueid The site model unique id string
+ * @param string $modelversionoutputdir The output dir of this model version
+ * @return null
+ */
+public function clear_model($uniqueid, $modelversionoutputdir);
+
+/**
+ * Delete the output directory.
+ *
+ * This method is called when a model is completely deleted.
+ *
+ * @param string $modeloutputdir The model directory id (parent of all model versions subdirectories).
+ * @param string $uniqueid The site model unique id string
+ * @return null
+ */
+public function delete_output_dir($modeloutputdir, $uniqueid);
+```
+
+### Classifier
+
+A [classifier](https://en.wikipedia.org/wiki/Statistical_classification) sorts input into two or more categories, based on analysis of the indicators. This is frequently used in binary predictions, e.g. course completion vs. dropout. This machine learning algorithm is "supervised": It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support classification. It extends the *Predictor* interface.
+
+Both these methods and *Predictor* methods should be implemented.
+
+```php
+/**
+ * Train this processor classification model using the provided supervised learning dataset.
+ *
+ * @param string $uniqueid
+ * @param \stored_file $dataset
+ * @param string $outputdir
+ * @return \stdClass
+ */
+public function train_classification($uniqueid, \stored_file $dataset, $outputdir);
+
+/**
+ * Classifies the provided dataset samples.
+ *
+ * @param string $uniqueid
+ * @param \stored_file $dataset
+ * @param string $outputdir
+ * @return \stdClass
+ */
+public function classify($uniqueid, \stored_file $dataset, $outputdir);
+
+/**
+ * Evaluates this processor classification model using the provided supervised learning dataset.
+ *
+ * @param string $uniqueid
+ * @param float $maxdeviation
+ * @param int $niterations
+ * @param \stored_file $dataset
+ * @param string $outputdir
+ * @param string $trainedmodeldir
+ * @return \stdClass
+ */
+public function evaluate_classification($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);
+```
+
+### Regressor
+
+A [regressor](https://en.wikipedia.org/wiki/Regression_analysis) predicts the value of an outcome (or dependent) variable based on analysis of the indicators. This value is linear, such as a final grade in a course or the likelihood a student is to pass a course. This machine learning algorithm is "supervised": It requires a training data set of elements whose classification is known (e.g. courses in the past with a clear definition of whether the student has dropped out or not). This is an interface to be implemented by machine learning backends that support regression. It extends *Predictor* interface.
+
+Both these methods and *Predictor* methods should be implemented.
+
+```php
+/**
+ * Train this processor regression model using the provided supervised learning dataset.
+ *
+ * @param string $uniqueid
+ * @param \stored_file $dataset
+ * @param string $outputdir
+ * @return \stdClass
+ */
+public function train_regression($uniqueid, \stored_file $dataset, $outputdir);
+
+/**
+ * Estimates linear values for the provided dataset samples.
+ *
+ * @param string $uniqueid
+ * @param \stored_file $dataset
+ * @param mixed $outputdir
+ * @return void
+ */
+public function estimate($uniqueid, \stored_file $dataset, $outputdir);
+
+
+/**
+ * Evaluates this processor regression model using the provided supervised learning dataset.
+ *
+ * @param string $uniqueid
+ * @param float $maxdeviation
+ * @param int $niterations
+ * @param \stored_file $dataset
+ * @param string $outputdir
+ * @param string $trainedmodeldir
+ * @return \stdClass
+ */
+public function evaluate_regression($uniqueid, $maxdeviation, $niterations, \stored_file $dataset, $outputdir);
+```
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-info.png b/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-info.png
new file mode 100644
index 0000000000..2d2b39bc1a
Binary files /dev/null and b/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-info.png differ
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-recommend.png b/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-recommend.png
new file mode 100644
index 0000000000..0b6147facc
Binary files /dev/null and b/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-recommend.png differ
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-starred.png b/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-starred.png
new file mode 100644
index 0000000000..b3aeb20f1d
Binary files /dev/null and b/versioned_docs/version-4.1/apis/plugintypes/mod/_activitymodule/activity-chooser-starred.png differ
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_files/index-php.mdx b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/index-php.mdx
new file mode 100644
index 0000000000..1ab22546c9
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/index-php.mdx
@@ -0,0 +1,2 @@
+
+The `index.php` should be used to list all instances of an activity that the current user has access to in the specified course.
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_files/index-php.tsx b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/index-php.tsx
new file mode 100644
index 0000000000..caebf44fb2
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/index-php.tsx
@@ -0,0 +1,52 @@
+/**
+ * Copyright (c) Moodle Pty Ltd.
+ *
+ * Moodle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Moodle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Moodle. If not, see
.
+ */
+import React from 'react';
+import { ComponentFileSummary } from '../../../../_utils';
+import type { Props } from '../../../../_utils';
+import DefaultDescription from './index-php.mdx';
+
+const defaultExample = `require_once('../../config.php');
+
+// The \`id\` parameter is the course id.
+$id = required_param('id', PARAM_INT);
+
+// Fetch the requested course.
+$course = $DB->get_record('course', ['id'=> $id], '*', MUST_EXIST);
+
+// Require that the user is logged into the course.
+require_course_login($course);
+
+$modinfo = get_fast_modinfo($course);
+
+foreach ($modinfo->get_instances_of('[modinfo]') as $instanceid => $cm) {
+ // Display information about your activity.
+}
+`;
+
+export default (initialProps: Props): ComponentFileSummary => (
+
+);
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.mdx b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.mdx
new file mode 100644
index 0000000000..c2bdec2fd8
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.mdx
@@ -0,0 +1,16 @@
+
+This file is used when adding/editing a module to a course. It contains the elements that will be displayed on the form responsible for creating/installing an instance of your module. The class in the file should be called `mod_[modname]_mod_form`.
+
+:::warning
+
+The `mod_[modname]_mod_form` is a current exception to the class autoloading rules.
+
+This will be addressed in [MDL-74472](https://tracker.moodle.org/browse/MDL-74472).
+
+:::
+
+:::info
+
+The following example gives a sample implementation of the creation form. It does **not** contain the full file.
+
+:::
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.tsx b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.tsx
new file mode 100644
index 0000000000..d47149d31a
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.tsx
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) Moodle Pty Ltd.
+ *
+ * Moodle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Moodle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Moodle. If not, see
.
+ */
+import React from 'react';
+import { ComponentFileSummary } from '../../../../_utils';
+import type { Props } from '../../../../_utils';
+import DefaultDescription from './mod_form-php.mdx';
+
+const defaultExample = `require_once($CFG->dirroot.'/course/moodleform_mod.php');
+require_once($CFG->dirroot.'/mod/certificate/lib.php');
+
+class mod_certificate_mod_form extends moodleform_mod {
+
+ function definition() {
+ global $CFG, $DB, $OUTPUT;
+
+ $mform =& $this->_form;
+
+ $mform->addElement('text', 'name', get_string('certificatename', 'certificate'), ['size'=>'64']);
+ $mform->setType('name', PARAM_TEXT);
+ $mform->addRule('name', null, 'required', null, 'client');
+
+ $ynoptions = [
+ 0 => get_string('no'),
+ 1 => get_string('yes'),
+ ];
+ $mform->addElement('select', 'usecode', get_string('usecode', 'certificate'), $ynoptions);
+ $mform->setDefault('usecode', 0);
+ $mform->addHelpButton('usecode', 'usecode', 'certificate');
+
+ $this->standard_coursemodule_elements();
+
+ $this->add_action_buttons();
+ }
+
+ }
+`;
+
+export default (initialProps: Props): ComponentFileSummary => (
+
+);
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.txt b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.txt
new file mode 100644
index 0000000000..b19839ef3f
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/mod_form-php.txt
@@ -0,0 +1,31 @@
+if (!defined('MOODLE_INTERNAL')) {
+ die('Direct access to this script is forbidden.'); // It must be included from a Moodle page
+}
+
+require_once($CFG->dirroot.'/course/moodleform_mod.php');
+require_once($CFG->dirroot.'/mod/certificate/lib.php');
+
+class mod_certificate_mod_form extends moodleform_mod {
+
+ function definition() {
+ global $CFG, $DB, $OUTPUT;
+
+ $mform =& $this->_form;
+
+ $mform->addElement('text', 'name', get_string('certificatename', 'certificate'), ['size'=>'64']);
+ $mform->setType('name', PARAM_TEXT);
+ $mform->addRule('name', null, 'required', null, 'client');
+
+ $ynoptions = [
+ 0 => get_string('no'),
+ 1 => get_string('yes'),
+ ];
+ $mform->addElement('select', 'usecode', get_string('usecode', 'certificate'), $ynoptions);
+ $mform->setDefault('usecode', 0);
+ $mform->addHelpButton('usecode', 'usecode', 'certificate');
+
+ $this->standard_coursemodule_elements();
+
+ $this->add_action_buttons();
+ }
+}
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_files/view-php.mdx b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/view-php.mdx
new file mode 100644
index 0000000000..96567c5f4a
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/view-php.mdx
@@ -0,0 +1,2 @@
+
+Moodle will automatically generate links to view the activity using the `/view.php` page and passing in an `id` value. The `id` passed is the course module ID, which can be used to fetch all remaining data for the activity instance.
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/_files/view-php.tsx b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/view-php.tsx
new file mode 100644
index 0000000000..28a608e8c3
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/_files/view-php.tsx
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) Moodle Pty Ltd.
+ *
+ * Moodle is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Moodle is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Moodle. If not, see
.
+ */
+import React from 'react';
+import { ComponentFileSummary } from '../../../../_utils';
+import type { Props } from '../../../../_utils';
+import DefaultDescription from './view-php.mdx';
+
+const defaultExample = `
+require('../../config.php');
+
+$id = required_param('id', PARAM_INT);
+[$course, $cm] = get_course_and_cm_from_cmid($id, '[modname]');
+$instance = $DB->get_record('[modname]', ['id'=> $cm->instance], '*', MUST_EXIST);
+`;
+
+export default (initialProps: Props): ComponentFileSummary => (
+
+);
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/activitymodule.md b/versioned_docs/version-4.1/apis/plugintypes/mod/activitymodule.md
new file mode 100644
index 0000000000..17a2a7510c
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/activitymodule.md
@@ -0,0 +1,77 @@
+---
+title: Activity chooser
+tags:
+- MUA Project
+documentationDraft: true
+---
+
+:::caution
+
+This documentation is from the project kick-off and has not been updated since the project completed.
+
+:::
+
+Through our road-map creation process of looking at highly voted tracker issues and relevant forum posts, as well as MUA interaction, an update to the activity chooser to simplify and make less intimidating, was chosen.
+
+[MDL-57828](https://tracker.moodle.org/browse/MDL-57828) was created and worked on, but unfortunately stalled, and did not complete its way through the integration process. There is a [substantial forum post](https://moodle.org/mod/forum/discuss.php?d=346664), with many suggestions and current pain points with the activity chooser. The MUA created a proposal issue ([MDL-61511](https://tracker.moodle.org/browse/MDL-61511)) to tackle the same issue.
+
+We have recently been analysing how course creation is achieved. Two main ideas were tested with focus groups to try and find the best away to approach course creation. With this information we are confident that we have a user focused design that will improve the activity chooser for everyone.
+
+We would like to invite everyone to express their opinion on this improvement. Course creation is a Moodle activity that is fundamental to teaching a course online, and we would like to ensure that the process is as easy and intuitive as possible.
+
+## Features
+
+The following are changes that we are planning on making in this project. We have a demo that can be viewed and interacted with.
+[Invisio mockup of the activity chooser](https://projects.invisionapp.com/share/SVSREPYNBYG#/screens/388682478).
+
+Our current work can be viewed at [activity chooser prototype](https://activitychooser.prototype.moodledemo.net/). Please take a look.
+
+### Larger display area
+
+The activity chooser will be wider and have the activities in a grid format. This allows for more activities to be seen at once.
+
+### Activities and resources are now merged
+
+Our research found that the distinction been activities and resources was not useful to teachers and so now these two categories have been merged together.
+
+### Starred / Favourites tab
+
+The user can now select activities to be added to the Starred tab. The starred tab is shown by default to users when pulling up the activity chooser.
+
+![The starred tab](./_activitymodule/activity-chooser-starred.png)
+
+### Recommended tab
+
+Site administrators will now be able to set a selection of activities as recommended. These recommended activities will show up in a tab in the activity chooser for the course creator to view. If no recommendations are made then this tab will not be displayed.
+
+![The recommended tab](./_activitymodule/activity-chooser-recommend.png)
+
+### Smart search bar
+
+To help find activities from the activity chooser, we will be adding a search bar, that will search through both the names of the activities, and also the information text, to try and find relevant activities that the user may want.
+
+### Other activity types
+
+Other activity types such as LTI will be able to be added to the activity chooser for the user to select.
+
+### Activity information hidden
+
+The information about an activity will be accessible through the 'i' icon. Clicking the link will show additional information about the activity. This will free up space for other activities to be shown rather than always taking up half of the activity chooser.
+
+![Additional information about an activity](./_activitymodule/activity-chooser-info.png)
+
+## Third party plugin developers
+
+Course module plugins can add items to the activity chooser by implementing the `{plugin}_get_content_items()` callback in their plugin lib (lib.php). This callback replaces the now deprecated `{plugin}_get_shortcuts()` method.
+
+In order for activity starring and recommendations to work, each content_item has an ID which is subject to some additional rules. Each ID:
+
+- Must be unique to your component.
+- Must not change.
+- Must be of type integer.
+
+See `lti_get_course_content_items()` for an example implementation in core.
+
+Additionally, for recommendations to be made, plugins must implement the `{plugin}_get_all_content_items()` callback in their lib.php. This method must return a list of all content items that can be added across all courses.
+
+Developers who are currently using the deprecated `{plugin}_get_shortcuts()` callback should implement the new callback in their plugins as soon as possible. Whilst legacy items are still included (in cases where the new callback has yet to be implemented in the plugin), these items can not be starred, nor recommended. Eventually all support for the deprecated method will be removed, as per normal deprecation policy.
diff --git a/versioned_docs/version-4.1/apis/plugintypes/mod/index.mdx b/versioned_docs/version-4.1/apis/plugintypes/mod/index.mdx
new file mode 100644
index 0000000000..6c5bc81718
--- /dev/null
+++ b/versioned_docs/version-4.1/apis/plugintypes/mod/index.mdx
@@ -0,0 +1,297 @@
+---
+title: Activity modules
+toc_max_heading_level: 4
+tags:
+ - API
+ - Activity
+ - Module
+ - mod
+---
+
+import {
+ BackupDir,
+ DbAccessPHP,
+ DbEventsPHP,
+ DbInstallXML,
+ DbMobilePHP,
+ DbUpgradePHP,
+ Lang,
+ Lib,
+ VersionPHP,
+} from '../../_files';
+
+import ModFormPHP from './_files/mod_form-php';
+import IndexPHP from './_files/index-php';
+import ViewPHP from './_files/view-php';
+
+Activity modules are a fundamental course feature and are usually the primary delivery method for learning content in Moodle.
+
+The plugintype of an Activity module is `mod`, and the frankenstyle name of a plugin is therefore `mod_[modname]`.
+
+All activity module plugins are located in the `/mod/` folder of Moodle.
+
+:::note
+
+The term `[modname]` is used as a placeholder in this documentation and should be replaced with the name of your activity module.
+
+:::
+
+## Folder layout
+
+Activity modules reside in the `/mod` directory.
+
+Each module is in a separate subdirectory and consists of a number of _mandatory files_ and any other files the developer is going to use.
+
+Below is an example of the file structure for the `folder` plugin.
+
+
+ View an example directory layout for the `folder` plugin.
+
+
+```console
+.
+├── backup
+│ ├── moodle1
+│ │ └── lib.php
+│ └── moodle2
+│ ├── backup_folder_activity_task.class.php
+│ ├── backup_folder_stepslib.php
+│ ├── restore_folder_activity_task.class.php
+│ └── restore_folder_stepslib.php
+├── classes
+│ ├── analytics
+│ │ └── indicator
+│ │ ├── activity_base.php
+│ │ ├── cognitive_depth.php
+│ │ └── social_breadth.php
+│ ├── content
+│ │ └── exporter.php
+│ ├── event
+│ │ ├── all_files_downloaded.php
+│ │ ├── course_module_instance_list_viewed.php
+│ │ ├── course_module_viewed.php
+│ │ └── folder_updated.php
+│ ├── external.php
+│ ├── privacy
+│ │ └── provider.php
+│ └── search
+│ └── activity.php
+├── db
+│ ├── access.php
+│ ├── install.php
+│ ├── install.xml
+│ ├── log.php
+│ ├── services.php
+│ └── upgrade.php
+├── download_folder.php
+├── edit.php
+├── edit_form.php
+├── index.php
+├── lang
+│ └── en
+│ └── folder.php
+├── lib.php
+├── locallib.php
+├── mod_form.php
+├── module.js
+├── phpunit.xml
+├── pix
+│ ├── icon.png
+│ └── icon.svg
+├── readme.txt
+├── renderer.php
+├── settings.php
+├── styles.css
+├── tests
+│ ├── backup
+│ │ └── restore_date_test.php
+│ ├── behat
+│ │ └── folder_activity_completion.feature
+│ ├── event
+│ │ └── events_test.php
+│ ├── externallib_test.php
+│ ├── generator
+│ │ └── lib.php
+│ ├── generator_test.php
+│ ├── lib_test.php
+│ ├── phpunit.xml
+│ └── search
+│ └── search_test.php
+├── version.php
+└── view.php
+```
+
+
+
+
+## Standard Files and their Functions
+
+There are several files that are crucial to Moodle. These files are used to install your module and then integrate it into Moodle. Each file has a particular function, some of the files are optional, and are only created if you want to use the functionality it offers. Below are the list of most commonly used files.
+
+### Backup Folder
+
+
+
+### `access.php` - Capability defaults
+
+export const accessExample = `
+$capabilities = [
+ 'mod/[modname]:addinstance' => [
+ 'riskbitmask' => RISK_XSS,
+ 'captype' => 'write',
+ 'contextlevel' => CONTEXT_COURSE,
+ 'archetypes' => [
+ 'editingteacher' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW,
+ ],
+ 'clonepermissionsfrom' => 'moodle/course:manageactivities',
+ ],
+ 'mod/[modname]:view' => [
+ 'captype' => 'read',
+ 'contextlevel' => CONTEXT_MODULE,
+ 'archetypes' => [
+ 'guest' => CAP_ALLOW,
+ 'student' => CAP_ALLOW,
+ 'teacher' => CAP_ALLOW,
+ 'editingteacher' => CAP_ALLOW,
+ 'manager' => CAP_ALLOW,
+ ],
+ ],
+];
+`;
+
+
+
+For activities the following capabilities are _required_:
+
+- `mod/[modname]:addinstance`: Controls whether a user may create a new instance of the activity
+- `mod/[modname]:view`: Controls whether a user may view an instance of the activity
+
+The example below shows the recommended configuration for the `addinstance` and `view` capabilities.
+
+This configuration will allow:
+
+- editing teachers and managers to create new instances, but not non-editing teachers.
+- all roles to view the activity.
+
+:::important
+
+Granting the view capability to archetypes like `guest` does not allow any user to view all activities. Users are still subject to standard access controls like course enrolment.
+
+:::
+
+For further information on what each attribute in that capabilities array means visit [NEWMODULE Adding capabilities](https://docs.moodle.org/dev/NEWMODULE_Adding_capabilities).
+
+
+ }
+/>
+
+### `events.php` - Event observers
+
+< DbEventsPHP />
+
+### `install.xml` - Database installation
+
+