<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Fox</id>
	<title>MoodleDocs - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://docs.moodle.org/dev/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Fox"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Fox"/>
	<updated>2026-06-04T10:44:43Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Moodle_4.0.2_release_notes&amp;diff=63521</id>
		<title>Talk:Moodle 4.0.2 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Moodle_4.0.2_release_notes&amp;diff=63521"/>
		<updated>2022-07-08T21:45:14Z</updated>

		<summary type="html">&lt;p&gt;Fox: Please adapt correctly interlanguage links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Lang links should point to 4.0.2 versions pages.&lt;br /&gt;
--[[User:Séverin Terrier|Séverin Terrier]] ([[User talk:Séverin Terrier|talk]]) 21:44, 8 July 2022 (UTC)&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.9.14_release_notes&amp;diff=62372</id>
		<title>Moodle 3.9.14 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.9.14_release_notes&amp;diff=62372"/>
		<updated>2022-05-09T17:39:23Z</updated>

		<summary type="html">&lt;p&gt;Fox: Released&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;This version of Moodle is no longer supported for general bug fixes.&#039;&#039;&#039; You are encouraged to [[:en:Upgrading|upgrade]] to a supported version of Moodle.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: 9 May 2022&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.9.14%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.9.14].&lt;br /&gt;
 &lt;br /&gt;
==Security fixes==&lt;br /&gt;
 	&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.9.13 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.9]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.9.14]]&lt;br /&gt;
[[es:Notas de Moodle 3.9.14]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.11.7_release_notes&amp;diff=62371</id>
		<title>Moodle 3.11.7 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.11.7_release_notes&amp;diff=62371"/>
		<updated>2022-05-09T17:38:36Z</updated>

		<summary type="html">&lt;p&gt;Fox: Released&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Release date: 9 May 2022&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.11.7%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.11.7].&lt;br /&gt;
==General fixes and improvements==&lt;br /&gt;
* MDL-69552 - Tag filter not working when adding random question from questionbank&lt;br /&gt;
* MDL-48633 - Lesson grade handling is buggy when scales in use&lt;br /&gt;
* MDL-58044 - Course completion report labels do not align correctly in RTL mode&lt;br /&gt;
* MDL-74299 - Unable to delete Questions from Question bank&lt;br /&gt;
* MDL-73979 - Timeline block views should display consistent information&lt;br /&gt;
* MDL-74127 - Attempts remaining for lesson are only displayed when &amp;quot;This page&amp;quot; is set to wrong answers&lt;br /&gt;
* MDL-74321 - Increased DB reads on forum &lt;br /&gt;
* MDL-74486 - Background images bleed into user tours&lt;br /&gt;
* MDL-57383 - Upload users admin tool incorrectly updates authentication method for existing users&lt;br /&gt;
* MDL-74258 - H5P activities not searchable by global search&lt;br /&gt;
* MDL-73874 - Drag and drop into text &amp;amp; Select missing words questions: form should validate &#039;multiple&#039; is on for choices used more than once&lt;br /&gt;
* MDL-69078 - The error when importing a GIFT question file with the wrong encoding does not make the problem clear&lt;br /&gt;
* MDL-74481 - LTI Advantage: Non-Editing Teacher has role Student&lt;br /&gt;
* MDL-74478 - Awarded badge for activity completion, despite not receiving a passing grade&lt;br /&gt;
* MDL-74436 - Fatal error when importing &amp;quot;course&amp;quot; events from ics file&lt;br /&gt;
* MDL-74427 - Coding error detected when deleting question category&lt;br /&gt;
==Security fixes==&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.11.6 release notes]]&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.11]]&lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.11.7]]&lt;br /&gt;
[[es:Notas de Moodle 3.11.7]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.10.11_release_notes&amp;diff=62370</id>
		<title>Moodle 3.10.11 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.10.11_release_notes&amp;diff=62370"/>
		<updated>2022-05-09T17:38:21Z</updated>

		<summary type="html">&lt;p&gt;Fox: Released&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;This version of Moodle is no longer supported for general bug fixes.&#039;&#039;&#039; You are encouraged to [[:en:Upgrading|upgrade]] to a supported version of Moodle.&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: 9 May 2022&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.10.11%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.10.11].&lt;br /&gt;
 &lt;br /&gt;
==Security fixes==&lt;br /&gt;
 	&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.10.10 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.10]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.10.11]]&lt;br /&gt;
[[es:Notas de Moodle 3.10.11]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0.1_release_notes&amp;diff=62369</id>
		<title>Moodle 4.0.1 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0.1_release_notes&amp;diff=62369"/>
		<updated>2022-05-09T17:37:51Z</updated>

		<summary type="html">&lt;p&gt;Fox: Released&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: 9 May 2022&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%224.0.1%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 4.0.1].&lt;br /&gt;
 &lt;br /&gt;
==General fixes and improvements==&lt;br /&gt;
* MDL-74461 - Not always possible to easily navigate back to section from an activity page&lt;br /&gt;
* MDL-74514 - BigbluebuttonBN is polling the BigblueButton server too often&lt;br /&gt;
* MDL-74481 - LTI Advantage: Non-Editing Teacher has role Student&lt;br /&gt;
* MDL-74478 - Awarded badge for activity completion, despite not receiving a passing grade&lt;br /&gt;
* MDL-74450 - The course secondary navigation should be displayed in the site home settings page&lt;br /&gt;
* MDL-74317 - Edit mode cannot be turned on/off when using other capabilities&lt;br /&gt;
* MDL-74436 - Fatal error when importing &amp;quot;course&amp;quot; events from ics file&lt;br /&gt;
* MDL-74427 - Coding error detected when deleting question category&lt;br /&gt;
 &lt;br /&gt;
==Security fixes==&lt;br /&gt;
 	&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 4.0 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 4.0]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de version de Moodle 4.0.1]]&lt;br /&gt;
[[es:Notas de Moodle 4.0.1]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Release_notes_template&amp;diff=62277</id>
		<title>Release notes template</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Release_notes_template&amp;diff=62277"/>
		<updated>2022-05-05T09:17:50Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link (to adapt if 4.x or 3.x)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Copy and paste this wiki code into the new release notes page and replace all the missing bits.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%22X.X.X%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in X.X.X].&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
===Database requirements===&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
===Browser support===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date.&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle X.X:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Other highlights==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==For admins==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==For developers==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
&lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle X.X.X-1 release notes]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle X.X]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Notes de version de Moodle X.X.X]]     (please use this for 4.x, and delete this tip and the line under)&lt;br /&gt;
[[fr:Notes de mise à jour de Moodle X.X.X]] (please use this for 3.x, and delete this tip and the line upper)&lt;br /&gt;
[[es:Notas de Moodle X.X.X]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Tips===&lt;br /&gt;
&lt;br /&gt;
The following git command can be used to find all upgrade.txt files that were modified since the last release, so that links to them can be provided in the release notes - typically in the For developers section.&lt;br /&gt;
&lt;br /&gt;
 $ git log --oneline --pretty=&amp;quot;format:&amp;quot; --name-only v3.5.0..v3.6.0-beta | grep upgrade.txt | sort | uniq | while read path; do echo &amp;quot;* [https://git.in.moodle.com/moodle/moodle/blob/v3.6.0-beta/$path $path]&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
See e.g. [[Moodle 3.6 release notes#Component APIs upgrades]] for how it was used in the past.&lt;br /&gt;
&lt;br /&gt;
[[:es:Plantilla para las notas de versiones|Plantilla en Español]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Processes|Release process]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0.1_release_notes&amp;diff=62275</id>
		<title>Moodle 4.0.1 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0.1_release_notes&amp;diff=62275"/>
		<updated>2022-05-05T08:36:08Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link (name changed since 4.0)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released - scheduled for 9 May 2022&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%224.0.1%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 4.0.1].&lt;br /&gt;
 &lt;br /&gt;
==General fixes and improvements==&lt;br /&gt;
* MDL-74461 - Not always possible to easily navigate back to section from an activity page&lt;br /&gt;
* MDL-74514 - BigbluebuttonBN is polling the BigblueButton server too often&lt;br /&gt;
* MDL-74481 - LTI Advantage: Non-Editing Teacher has role Student&lt;br /&gt;
* MDL-74478 - Awarded badge for activity completion, despite not receiving a passing grade&lt;br /&gt;
* MDL-74450 - The course secondary navigation should be displayed in the site home settings page&lt;br /&gt;
* MDL-74317 - Edit mode cannot be turned on/off when using other capabilities&lt;br /&gt;
* MDL-74436 - Fatal error when importing &amp;quot;course&amp;quot; events from ics file&lt;br /&gt;
* MDL-74427 - Coding error detected when deleting question category&lt;br /&gt;
 &lt;br /&gt;
==Security fixes==&lt;br /&gt;
 	&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 4.0 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 4.0]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de version de Moodle 4.0.1]]&lt;br /&gt;
[[es:Notas de Moodle 4.0.1]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:DevDocs_Migration&amp;diff=61963</id>
		<title>Category:DevDocs Migration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:DevDocs_Migration&amp;diff=61963"/>
		<updated>2022-04-12T12:00:35Z</updated>

		<summary type="html">&lt;p&gt;Fox: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle is currently assessing options for improving Developer Documentation and resources.&lt;br /&gt;
&lt;br /&gt;
As a part of this assessment we are also assessing alternatives to WikiMedia for this documentation and are migrating some of the content in this wiki into the systems we have under assessment.&lt;br /&gt;
&lt;br /&gt;
To keep track of the pages that have been migrated, and to help consider how such a migration could be managed, we have created a new Category for the migration, as this will allow us to find and identify any documentation which has or has not been moved. In the event that we do adopt one of the systems that we are exploring it is hoped that we will also be able to make use of any transitioned documents, and apply any updates since the change was made.&lt;br /&gt;
&lt;br /&gt;
More information on any changes will be announced at a later date.&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=61517</id>
		<title>Moodle 4.0 developer update</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=61517"/>
		<updated>2021-11-17T14:11:11Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* Introduction of a new activity icons */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 4.0}}This page highlights the important changes that are coming in Moodle 4.0 for developers. Including how the UX improvements impact custom themes, relevant API changes, and what you can do as developer to prepare for the 4.0 release.&lt;br /&gt;
== Theme changes ==&lt;br /&gt;
The 4.0 theme changes can be classified as changes to improve overall navigation, changes for the course navigation and page, and general UI improvements for Moodle 4.0 and newer only.&lt;br /&gt;
==== Navigation UI changes ====&lt;br /&gt;
A new layout has been added that pushes the blocks region offscreen called the drawers layout. This layout has a fixed width of 800px for the main content area and page buttons to open / close the drawers. Files:&lt;br /&gt;
 /theme/boost/layouts/drawers.php&lt;br /&gt;
 /theme/boost/templates/drawers.mustache&lt;br /&gt;
In case a page uses “fake blocks” (for example book, quiz, calendar, etc.) the drawer region will be opened automatically on first visit.&lt;br /&gt;
&lt;br /&gt;
Child themes implementing this layout should update the theme config.php and configure the ‘drawers’ layout from theme boost for pages like ‘course’ and ‘incourse’&lt;br /&gt;
&lt;br /&gt;
Pages that should not use the drawers layout are the admin pages or other pages that require more horizontal space in the main content area.&lt;br /&gt;
===== Primary / secondary navigation =====&lt;br /&gt;
The top navbar now includes the new &#039;&#039;&#039;primary navigation&#039;&#039;&#039;, this navigation used to be in the page navdrawer region. If custommenu items are configured in the global theme settings they will be added to the primary navigation.&lt;br /&gt;
&lt;br /&gt;
The main content area shows tabs for secondary navigation with a maximum of 5 items being rendered in this ‘more’ menu. A new UI component has been created to render menus like this. Files:&lt;br /&gt;
 /lib/templates/moremenu.mustache&lt;br /&gt;
===== Navigation upcoming changes =====&lt;br /&gt;
===== Edit switch. =====&lt;br /&gt;
MDL-71610&lt;br /&gt;
&lt;br /&gt;
On theme boost the “Turn editing on” and  “Customise this page” buttons have been replaced by an edit switch in the top navbar. Theme Classic will keep using the old buttons. Child themes can choose to use the edit switch if the theme config.php is using this variable&lt;br /&gt;
 $THEME-&amp;gt;haseditswitch = true;&lt;br /&gt;
The languague menu, which used to be rendered in place of the custom menu has moved to the user dropdown when the user is logged in. If not logged in it will be placed next to the search / notification / messaging icon in the top navbar.&lt;br /&gt;
==== Course navigation and the course page ====&lt;br /&gt;
===== Introduction of a new course index component =====&lt;br /&gt;
The new course index feature can be themed using a set of scss variables. Use them to change the look and feel instead of adding custom css&lt;br /&gt;
 /theme/boost/scss/moodle/courseindex.scss&lt;br /&gt;
With the introduction of the course index component, the previous and next links shown underneath each activity are no longer needed and they will be removed.&lt;br /&gt;
===== Introduction of a new activity icons =====&lt;br /&gt;
The icons used for activities have been redesigned and updated for all core moodle activities.&lt;br /&gt;
&lt;br /&gt;
When viewing the new icons in a file manager, for example for the quiz activity, you will see a simple black monochrome icon with a transparent background.&lt;br /&gt;
&lt;br /&gt;
On the course page, or in the activity chooser, the icon will display as a white icon on a coloured background. Styling of the icons on the coursepage is controlled by the css in theme/boost/scss/moodle/icons.scss.&lt;br /&gt;
&lt;br /&gt;
The background colour for activity icons is set using a new variable in function [modname]_supports(). The quiz activity is of type assessment, so in function quiz_supports() there is a new line defining the purpose:&lt;br /&gt;
 case FEATURE_MOD_PURPOSE: return MOD_PURPOSE_ASSESSMENT;&lt;br /&gt;
Available purposes are:&lt;br /&gt;
&lt;br /&gt;
* MOD_PURPOSE_COMMUNICATION&lt;br /&gt;
* MOD_PURPOSE_ASSESSMENT&lt;br /&gt;
* MOD_PURPOSE_COLLABORATION&lt;br /&gt;
* MOD_PURPOSE_CONTENT&lt;br /&gt;
* MOD_PURPOSE_ADMINISTRATION&lt;br /&gt;
* MOD_PURPOSE_INTERFACE&lt;br /&gt;
&lt;br /&gt;
The background colours linked to these purposes are set in theme/boost/scss/moodle/variables.scss&lt;br /&gt;
 $activity-icon-colors: map-merge(&lt;br /&gt;
     (&lt;br /&gt;
         &amp;quot;administration&amp;quot;: #5d63f6,&lt;br /&gt;
         &amp;quot;assessment&amp;quot;: #eb66a2,&lt;br /&gt;
         &amp;quot;collaboration&amp;quot;: #f7634d,&lt;br /&gt;
         &amp;quot;communication&amp;quot;: #11a676,&lt;br /&gt;
         &amp;quot;content&amp;quot;: #399be2,&lt;br /&gt;
         &amp;quot;interface&amp;quot;: #a378ff&lt;br /&gt;
     ),&lt;br /&gt;
     $activity-icon-colors&lt;br /&gt;
 );&lt;br /&gt;
If activity plugins do not define FEATURE_MOD_PURPOSE the activity icon will be rendered against a light grey background. There is no requirement to define the purpose of activity plugins, it will only affect the icon styling.&lt;br /&gt;
&lt;br /&gt;
Customising the activity icon can be done in an alternative way. For example using the styles.css in mod/[pluginname/styles.css&lt;br /&gt;
&lt;br /&gt;
In the example below the activity plugin developer chooses to keep the coloured icon for the activity and render it as large as the coloured background on the core activities&lt;br /&gt;
 .modicon_subcourse.activityiconcontainer {&lt;br /&gt;
     background-color: transparent;&lt;br /&gt;
     padding: 0;&lt;br /&gt;
 }&lt;br /&gt;
  &lt;br /&gt;
 .modicon_subcourse.activityiconcontainer img {&lt;br /&gt;
     width: 50px;&lt;br /&gt;
     height: 50px;&lt;br /&gt;
 }&lt;br /&gt;
To customize all icon colours use this scss array and add it to the ‘Raw initial SCSS’ in the theme Boost advanced settings page. The complete array of icon background colours can be overridden using the ‘Raw initial SCSS’ in the theme settings page. The example below changes the colours of each activity type.&lt;br /&gt;
 $activity-icon-colors: (&lt;br /&gt;
     &amp;quot;administration&amp;quot;: #5D63F6,&lt;br /&gt;
     &amp;quot;assessment&amp;quot;: #11A676,&lt;br /&gt;
     &amp;quot;collaboration&amp;quot;: #EB66A2,&lt;br /&gt;
     &amp;quot;communication&amp;quot;: #F7634D,&lt;br /&gt;
     &amp;quot;content&amp;quot;: #399BE2,&lt;br /&gt;
     &amp;quot;interface&amp;quot;: #A378FF&lt;br /&gt;
 )&lt;br /&gt;
&lt;br /&gt;
===== General UI improvements upcoming changes =====&lt;br /&gt;
===== Login page =====&lt;br /&gt;
MDL-69371&lt;br /&gt;
&lt;br /&gt;
The login page has been redesigned and allows the admin to configure a background image for the login page only in the theme settings page. This change is available in both Boost and Classic. The login page still has all the features with an improved layout. &lt;br /&gt;
===== The page footer =====&lt;br /&gt;
MDL-71965&lt;br /&gt;
&lt;br /&gt;
In large screens, the page footer button is only visible when clicking a help button at the bottom right of the screen.&lt;br /&gt;
===== User initials as profile picture placeholder =====&lt;br /&gt;
MDL-72305&lt;br /&gt;
&lt;br /&gt;
If users do not upload a profile picture the user initials are displayed on a rounded gray background as a placeholder picture in the top navbar or any other page using a placeholder image. This change will be available in both Boost and Classic. &lt;br /&gt;
&lt;br /&gt;
With the introduction of this placeholder image the full username will no longer be displayed in the top navbar.&lt;br /&gt;
&lt;br /&gt;
===== Removal of back to top link =====&lt;br /&gt;
MDL-72454&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;back to top&amp;quot; link will be removed for theme boost since the new course index reduced the dependence on page scrolling. Also, the new footer is positioned where this component used to be.&lt;br /&gt;
===== Styling changes =====&lt;br /&gt;
By default rounded edges will be used for UI components MDL-72455, for the page header and main content area the borders will be removed MDL-72457. &lt;br /&gt;
== Component library ==&lt;br /&gt;
==== Purpose of the Component Library ====&lt;br /&gt;
Each Moodle installation now ships with a Moodle User Interface (UI) Component library, a documentation system used to describe all the Bootstrap components and the custom Moodle components. The component Library is a helper tool for developers when creating user interfaces, a testing tool for theme developers and a documentation tool for core developers. The ultimate goal of having a component library is to encourage developers to create consistent user interfaces to improve Moodle’s overall user experience.&lt;br /&gt;
&lt;br /&gt;
The library contains pages with documentation about User Interface components. It contains details on how to use the component, what variations are available and the JavaScript events / options are associated with the component.&lt;br /&gt;
&lt;br /&gt;
When writing on these pages it is possible to render core mustache templates using some custom syntax like this:&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{&amp;lt; mustache template=&amp;quot;core/notification_error&amp;quot; &amp;gt;}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;{{&amp;lt; /mustache &amp;gt;}}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
You can also call core JavaScript or use HTML examples where the html code and the rendered result are visible in the Component Library. For more info visit the [http://componentlibrary.moodle.com/admin/tool/componentlibrary/docspage.php/library/moodle-templates/ Moodle templates] page or the [http://componentlibrary.moodle.com/admin/tool/componentlibrary/docspage.php/library/moodle-javascript/ Moodle JavaScript] page.&lt;br /&gt;
&lt;br /&gt;
Each page in the library uses the current css from the default theme in your Moodle installation, if you have multiple themes installed and enabled the setting &amp;quot;Allow theme changes on url&amp;quot;, the component library will have a theme selector option.&lt;br /&gt;
===== Enabling the Component Library =====&lt;br /&gt;
Component library pages are written in the markdown language. These pages need to be compiled to HTML pages before the Component Library is visible. To compile the pages the server running Moodle needs to have the [[Javascript Modules#Install%20NVM%20and%20Node|JavaScript developer tools installed]] (nodeJs and Grunt)&lt;br /&gt;
&lt;br /&gt;
If your server meets all requirements you can enable the library running&lt;br /&gt;
 $ npm install&lt;br /&gt;
 $ grunt componentlibrary&lt;br /&gt;
Further installation instructions can be found in the Component Library itself.&lt;br /&gt;
===== The online version of the Component Library =====&lt;br /&gt;
A hosted version of the Component Library can be found here. http://componentlibrary.moodle.com&lt;br /&gt;
===== Documenting new UI Components =====&lt;br /&gt;
There are no set rules for adding new pages in the component library yet. These rules will need to be written and adopted in the integration process for Moodle code.&lt;br /&gt;
&lt;br /&gt;
As a guideline for making this rules consideration are:&lt;br /&gt;
&lt;br /&gt;
The component library is not about single use components, for example the Moodle grade book (a huge component with many custom features). Or about very common components like buttons, these are already covered by the Bootstrap section of the component library.&lt;br /&gt;
&lt;br /&gt;
New features should be build keeping in mind the UI part needs to be customisable and if possible (and making sense) reusable. And example would be the new page drawers that we are introducing for the Navigation project. Or the custom primary navigation menus where overflowing items are pushed into a More section.&lt;br /&gt;
== Navigation ==&lt;br /&gt;
The core Navigation API has been left mostly untouched. The callbacks to all navigation callbacks remains unchanged and will be called as part of the regular &#039;navigation&#039; and &#039;settingsnav&#039; initialisation. Some new core classes have been created and exist within a new namespace &#039;core/navigation&#039; and serves as conduit to rearrange, cherry-pick existing navigation nodes from the navigation/settingsnav trees and display within the respective navigation type. As such, it is highly recommended to provide unique keys for custom navigation nodes as this helps in the cherry-picking / rearranging process within the new classes.&lt;br /&gt;
===== Primary navigation / Primary Output =====&lt;br /&gt;
The primary navigation(the navbar) apart from the existing content will now display links to the Dashboard, My Courses, Site Admin and Course search, by default. You can still add items to the navbar via the &#039;custom menu&#039; option. This will be displayed within the &#039;More&#039; menu. We have transitioned the menus to be rendered via templates - refer user_menu.mustache. The lang menu has been moved to reside within the user menu.&lt;br /&gt;
===== New view =====&lt;br /&gt;
All settings for courses/modules will now be displayed as tabs within the module. A predefined set of tabs will be shown with any remaining / newly added ones residing within the &#039;Course Admin&#039; page. The settings cog will not be shown anymore. It is recommended to review any settings as some might be displayed as tabs and possibly move them to the tertiary navigation as is done in the core activity modules&amp;lt;sup&amp;gt;1&amp;lt;/sup&amp;gt;. At most 5 tabs will be displayed to a user with all the overflow nodes now residing within the &#039;More&#039; menu. Some of the nodes can be hidden by using the new functions defined. &lt;br /&gt;
===== New API functions =====&lt;br /&gt;
====== Page API ======&lt;br /&gt;
* Magic getters to fetch the primary and secondary navs and the primary output.&lt;br /&gt;
* The secondarynav magic getter also checks whether a custom secondary class has been defined within the module&#039;s local\views directory. Use this if you want to deviate from the standard secondary nav structure/order.&lt;br /&gt;
&lt;br /&gt;
* set_secondary_nav - Force override the secondary navigation class&lt;br /&gt;
&lt;br /&gt;
* has_secondary_navigation_setter - Sets the ‘_hassecondarynavigation’ to indicate whether a page should render the secondary navigation&lt;br /&gt;
====== Navigationlib ======&lt;br /&gt;
* set_show_in_secondary_navigation - whether or not a node should be displayed in the secondary nav. Accepts a single boolean argument&lt;br /&gt;
* set_force_into_more_menu- whether or not to force a node into the &#039;More&#039; menu. Accepts a single boolean argument&lt;br /&gt;
===== Changing order of tabs in secondary navigation nodes =====&lt;br /&gt;
Apart from the previously mentioned functions, you can also create a custom secondary class as mentioned earlier. This will automatically be picked by getter and used to render the secondary nav within the activity. E.g. mod_assign/local/views/secondary. Note: This is currently only possible on an activity and block level. &lt;br /&gt;
===== Upcoming changes: =====&lt;br /&gt;
# &amp;lt;sup&amp;gt;1 -&amp;lt;/sup&amp;gt; Complete tertiary nav overhaul for core’s modules - MDL-71912. MDL-71913, MDL-71914, MDL-71915&lt;br /&gt;
# Backwards compatibility for complex deep nested custom navigation. Any custom navigation added by 3rd party devs will now be displayed as flatter structure within a URL select - MDL-72352&lt;br /&gt;
# New module API to inject common content at the top of a module page. The common content would be the title, description and activity information. This solves 2 issues:&lt;br /&gt;
## A centralised location where we can handle #2 and inject it into the relevant page&lt;br /&gt;
## A centralised location where we can inject items particularly activity_information without the need to be replicated in each module. &lt;br /&gt;
== The core_courseformat subsystem ==&lt;br /&gt;
Most of the logic for rendering and editing a course has been moved to a new subsystem called courseformat. The subsystem is located in &amp;quot;course/format&amp;quot; folder so it includes all the format plugins inside. The methods and modules which are distributed between the course and the course/format folders are now rearranged or refactored to be aligned with the current Moodle coding style.&lt;br /&gt;
==== Mandatory renderer in course formats ====&lt;br /&gt;
Now format plugins renderer is not optional anymore. Legacy formats without a renderer will get a deprecation message but it will continue working however, they should create a new renderer as soon as possible. The section-based format can do it by extending the provided core_courseformat\output\section_renderer class which includes all the necessary methods.&lt;br /&gt;
==== New format base class ====&lt;br /&gt;
The old base_format class (which all plugins extend) is now renamed as core_courseformat\base. The new class provides all the functionally of the previous base_format but it has been refactored to be used as a centralized source of truth for the course rendering. Legacy formats should extend the new class to avoid the deprecation message.&lt;br /&gt;
&lt;br /&gt;
Now, the plugin format class provides information such as:&lt;br /&gt;
* If the page is displaying a single or multiple section&lt;br /&gt;
* Give access to other related format objects like the modinfo, the course record, maximum number of sections...&lt;br /&gt;
* If the format is compatible with features like course index, reactive components, ajax...&lt;br /&gt;
* Other format specifics like the page title, the default section name, default blocks...&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The format instance is now the main object output components will use to render a course (see next section for more information).&lt;br /&gt;
==== New course output classes and mustache files ====&lt;br /&gt;
Traditionally, section-based course formats uses print_single_section_page and print_multiple_section_page to render the course content. In Moodle 4.0 most of the course rendering methods are migrated to output components and mustache templates. The old methods will get deprecation messages if they use the old renderer methods.&lt;br /&gt;
&lt;br /&gt;
This is an example of a format rendering a course:&amp;lt;syntaxhighlight lang=&amp;quot;php-brief&amp;quot;&amp;gt;&lt;br /&gt;
// Get the course format instance.&lt;br /&gt;
$format = course_get_format($course);&lt;br /&gt;
&lt;br /&gt;
// Get the specific format renderer.&lt;br /&gt;
$renderer = $format-&amp;gt;get_renderer($PAGE);&lt;br /&gt;
&lt;br /&gt;
if (!empty($displaysection)) {&lt;br /&gt;
    // Setup the format instance to display a single section.&lt;br /&gt;
    $format-&amp;gt;set_section_number($displaysection);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Create the ouptut instance and render it.&lt;br /&gt;
$outputclass = $format-&amp;gt;get_output_classname(&#039;content&#039;);&lt;br /&gt;
$widget = new $outputclass($format);&lt;br /&gt;
&lt;br /&gt;
echo $renderer-&amp;gt;render($widget);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;Format plugins are free to use its own output classes to render a course, or they could override the existing output classes by providing their own implementation. For example, the default output for &amp;quot;content&amp;quot; (as in the previous example) is &amp;quot;core_courseformat\output\local\|content&amp;quot;, however, if the plugin has a &amp;quot;format_XXX\output\courseformat\content&amp;quot; class, the $format-&amp;gt;class the get_output_class will return the overridden one.&lt;br /&gt;
Another important update on course rendering is that now all course structure is rendered using mustache templates instead of the original html_writer methods. Now themes are able to override the course format by providing alternative versions of the mustache files. All core course templates are located in &amp;quot;course/format/templates&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
All the new output classes and a guide on how to migrate the current third-party plugins will be available soon.&lt;br /&gt;
==== Course editor javascript modules and frontend components ====&lt;br /&gt;
The majority of the javascript logic related to the course editing is replaced by AMD modules. Because this is a major change in the way courses are edited and rendered, by default format plugins will continue using the previous YUI modules for now. However, formats can start using the new libraries overriding the &amp;quot;$format-&amp;gt;supports_components()&amp;quot; method.&lt;br /&gt;
&lt;br /&gt;
Some Moodle 4.0 new features are only available for courses using the new editor library:&lt;br /&gt;
* Edit the course via the course index&lt;br /&gt;
* Creating sections without reloading the course page&lt;br /&gt;
* The new move section/activity modal&lt;br /&gt;
* Native browser drag&amp;amp;drop implementation&lt;br /&gt;
The new course editor uses a component-based reactive pattern to keep track of the course changes. The pattern highlights are:&lt;br /&gt;
* The main AMD module &amp;quot;core_crouseformat\courseeditor&amp;quot; maintains a data structure called state.&lt;br /&gt;
* Each UI element is implemented as a Component that observes the course state data and reacts to any data change&lt;br /&gt;
* When any reactive component needs to modify the course, it asks the course editor to execute a mutation. Mutations encapsulate all web services calls and alter the course state data.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The reactive library documentation, as well as the format plugin migration guide, will be available soon.&lt;br /&gt;
==== Other course related 4.0 changes ====&lt;br /&gt;
Two new web services have been added:&lt;br /&gt;
* core_courseformat_get_state: user by the new javascript course editor to get the current course state data (containing the list of sections, activities, and other course-related data)&lt;br /&gt;
* core_courseformat_update_course: to alter the current course content. Each call returns the parts of the course state altered by the action&lt;br /&gt;
== API changes ==&lt;br /&gt;
== Behat changes ==&lt;br /&gt;
To make behat tests more readable and easy to maintain, it is recommended to use the most direct steps to get what the test needs. So since MDL-66335 was integrated, and the step was improved in MDL-72179 is highly recommended to use&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
instead of navigating to the activity via&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
Now that [https://docs.moodle.org/dev/Prototypes#Course_creation_improvements Course index] (MDL-71209) is integrated but the project is not stable, these behat steps&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
will fail using Boost theme.&lt;br /&gt;
&lt;br /&gt;
The reason for it is that the drawer used in Boost is hiding the course index. So when the test is trying to follow an &amp;quot;Activity name&amp;quot; link, it finds two different links:&lt;br /&gt;
* one in the course index&lt;br /&gt;
* another one in the course main content.&lt;br /&gt;
But the first one, the one in the course index, is hidden by the drawer, and the test fails.&lt;br /&gt;
&lt;br /&gt;
However the recommended behat steps&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
work &#039;&#039;&#039;fine&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Some of the failing behats are fixed in https://github.com/ferranrecio/moodle/commit/c79d58a50b48aa6891ff1d3ba92a7b0ab2393c88#diff-fdf8b0b1eade3b69eaad038de0ddd7c8dec2be7afa32dc693fb929739a49fa9dR32 - MDL-71209&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
 And I am on the &amp;quot;Test assignment name&amp;quot; &amp;quot;assign activity&amp;quot; page logged in as teacher1&lt;br /&gt;
instead of:&lt;br /&gt;
 When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
 And I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 And I follow &amp;quot;Test assignment name&amp;quot;&lt;br /&gt;
== Core plugins review ==&lt;br /&gt;
A few plugins from core Moodle LMS which are no longer or hardly used have been removed and, if appropriate, added to the Moodle plugins directory.&lt;br /&gt;
&lt;br /&gt;
More information about this project, the list of plugins to be removed and the process to follow for keeping them before upgrading to 4.0 can be found in the [[Core plugins review]] page.&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0_release_notes&amp;diff=61483</id>
		<title>Moodle 4.0 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0_release_notes&amp;diff=61483"/>
		<updated>2021-11-03T09:33:39Z</updated>

		<summary type="html">&lt;p&gt;Fox: Updated version to 4.0&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released - scheduled for January 2022&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%224.0%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 4.0].&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from a previous version, please see [[:en:Upgrading|Upgrading]] in the user docs.&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Requirements still to be reviewed and updated as necessary!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.6 or later&lt;br /&gt;
* PHP version: minimum PHP 7.3.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.10&#039;&#039;. PHP 7.4.x is supported too. [[Moodle and PHP|PHP 8.0 support]] is being implemented (see MDL-70745) and &#039;&#039;&#039;not ready for production&#039;&#039;&#039; yet.&lt;br /&gt;
* PHP extension &#039;&#039;&#039;sodium&#039;&#039;&#039; is recommended. It will be required in Moodle 4.2. For further details, see [https://docs.moodle.org/311/en/Environment_-_PHP_extension_sodium Environment - PHP extension sodium].&lt;br /&gt;
* PHP extension &#039;&#039;&#039;exif&#039;&#039;&#039; is recommended.&lt;br /&gt;
* PHP setting &#039;&#039;&#039;max_input_vars&#039;&#039;&#039; is recommended to be &amp;gt;= 5000 for PHP 7.x installations. It&#039;s a requirement for PHP 8.x installations. For further details, see [https://docs.moodle.org/311/en/Environment_-_max_input_vars Environment - max input vars].&lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 10 (increased since Moodle 3.11)  &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.7 &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 10.2.29 &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2017 (increased since Moodle 3.10)&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 11.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Moodle 4.0 does NOT support Internet Explorer 11.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Safari 7 and below has known compatibility issues with Moodle 4.0.&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date.&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other highlights==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.11 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 4.0]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de version de Moodle 4.0]]&lt;br /&gt;
[[es:Notas de Moodle 4.0]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0_release_notes&amp;diff=61482</id>
		<title>Moodle 4.0 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0_release_notes&amp;diff=61482"/>
		<updated>2021-11-03T09:20:16Z</updated>

		<summary type="html">&lt;p&gt;Fox: Changed release date + updated french link (since 4.0)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released - scheduled for January 2022&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%224.0%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 4.0].&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from a previous version, please see [[:en:Upgrading|Upgrading]] in the user docs.&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Requirements still to be reviewed and updated as necessary!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.6 or later&lt;br /&gt;
* PHP version: minimum PHP 7.3.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.10&#039;&#039;. PHP 7.4.x is supported too. [[Moodle and PHP|PHP 8.0 support]] is being implemented (see MDL-70745) and &#039;&#039;&#039;not ready for production&#039;&#039;&#039; yet.&lt;br /&gt;
* PHP extension &#039;&#039;&#039;sodium&#039;&#039;&#039; is recommended. It will be required in Moodle 4.2. For further details, see [https://docs.moodle.org/311/en/Environment_-_PHP_extension_sodium Environment - PHP extension sodium].&lt;br /&gt;
* PHP extension &#039;&#039;&#039;exif&#039;&#039;&#039; is recommended.&lt;br /&gt;
* PHP setting &#039;&#039;&#039;max_input_vars&#039;&#039;&#039; is recommended to be &amp;gt;= 5000 for PHP 7.x installations. It&#039;s a requirement for PHP 8.x installations. For further details, see [https://docs.moodle.org/311/en/Environment_-_max_input_vars Environment - max input vars].&lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 10 (increased since Moodle 3.11)  &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.7 &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 10.2.29 &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2017 (increased since Moodle 3.10)&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 11.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Moodle 3.10 does NOT support Internet Explorer 11.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Safari 7 and below has known compatibility issues with Moodle 3.10.&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date.&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other highlights==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.11 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 4.0]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de version de Moodle 4.0]]&lt;br /&gt;
[[es:Notas de Moodle 4.0]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.10.7_release_notes&amp;diff=61267</id>
		<title>Moodle 3.10.7 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.10.7_release_notes&amp;diff=61267"/>
		<updated>2021-09-10T14:02:41Z</updated>

		<summary type="html">&lt;p&gt;Fox: Undo revision 61262 by Tsala (talk)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released - scheduled for 13 September 2021&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.10.7%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.10.7].&lt;br /&gt;
 &lt;br /&gt;
==General fixes and improvements==&lt;br /&gt;
* MDL-70176 - Forum Grading Does Not Respect Separate Groups Filter&lt;br /&gt;
* MDL-71121 - Default settings async course backup&lt;br /&gt;
* MDL-49202 - Checking &amp;quot;Hidden&amp;quot; in grade item settings does not hide the item from student, at the same time selecting &amp;quot;Hide&amp;quot; from dropdown on the setup page does&lt;br /&gt;
* MDL-72242 - Missing SVG files in forum posts&lt;br /&gt;
* MDL-70376 - Assignment - Annotated PDF Download issues when page is turned&lt;br /&gt;
* MDL-72312 - PHP 7.2 tests failing in 3.10 &amp;amp; 3.9, caused by buggy php-igbinary extension&lt;br /&gt;
* MDL-71500 - Cannot select a date on the right hand side 3 month mini calendar, after previously selecting one&lt;br /&gt;
* MDL-69451 - moodle_read_slave_trait: restore temptables object when creating rw and ro handles&lt;br /&gt;
* MDL-72033 - User tours: step placement issues if screen too narrow&lt;br /&gt;
* MDL-71973 - Exception thrown when evaluating disabled models from the CLI&lt;br /&gt;
* MDL-70006 - Suspended enrolment will get analytics messages&lt;br /&gt;
* MDL-70165 - Unable to change user role in a new course&lt;br /&gt;
* MDL-70433 - In gradebook titles, ampersand &#039;&amp;amp;&#039; is being displayed as &amp;amp; amp;&lt;br /&gt;
* MDL-71050 - H5P does not use the correct language&lt;br /&gt;
* MDL-72265 - Backup code added in MDL-56310 incorrectly checks moodle/role:safeoverride for users who already have moodle/role:override&lt;br /&gt;
* MDL-67833 - Text run over on Lang customization screen&lt;br /&gt;
* MDL-72035 - Course completion report Excel download should include BOM to ensure correct character encoding&lt;br /&gt;
* MDL-71945 - Bulk releasing grades for anonymous submissions pushes them to gradebook&lt;br /&gt;
* MDL-71844 - Navigation breadcrumbs lost when running single task&lt;br /&gt;
* MDL-71487 - Setting filesize settings to huge values breaks settings pages/search&lt;br /&gt;
* MDL-72207 - Webservice mod_assign_get_submission_status doesn&#039;t support &amp;quot;All participants&amp;quot;&lt;br /&gt;
* MDL-71029 - Forum summary report multiplies counts by number of enrollments a user has&lt;br /&gt;
* MDL-72271 - Clicking &amp;quot;Finish Review&amp;quot; after a quiz set to Full screen popup with Javascript security results in a 404 to /mod/quiz/0 if not in a popup window&lt;br /&gt;
* MDL-72325 - sitepolicynotagreed popup appears when trying to start a user tour&lt;br /&gt;
* MDL-72153 - Privacy export of user data doesn&#039;t export description files correctly/triggers debugging&lt;br /&gt;
* MDL-72106 - Error being displayed after deleting calendar subscription&lt;br /&gt;
&lt;br /&gt;
==Accessibility improvements==&lt;br /&gt;
* MDL-68639 - Atto produces invalid nested unordered (UL) lists&lt;br /&gt;
* MDL-72286 - Atto plugin steals default submit action so enter key in other fields no longer submits the form&lt;br /&gt;
* MDL-71674 - Atto editor&#039;s insert image dialog boxes do not show all error messages&lt;br /&gt;
* MDL-71656 - Add meaningful label to colour items in colour chooser elements&lt;br /&gt;
* MDL-72206 - Insufficient colour contrast in warning messages in environment check&lt;br /&gt;
* MDL-71814 - Atto: File picker – file info panel focus issue&lt;br /&gt;
&lt;br /&gt;
==Security improvements==&lt;br /&gt;
* MDL-72014 - Update grunt and some components to avoid some security reports&lt;br /&gt;
* MDL-72187 - Log visibility change of log stores&lt;br /&gt;
 &lt;br /&gt;
==Security fixes==&lt;br /&gt;
 	&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.10.6 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.10]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.10.7]]&lt;br /&gt;
[[es:Notas de Moodle 3.10.7]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.11.3_release_notes&amp;diff=61266</id>
		<title>Moodle 3.11.3 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.11.3_release_notes&amp;diff=61266"/>
		<updated>2021-09-10T13:59:22Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* Accessibility improvements */  Delete line in double&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released - scheduled for 13 September 2021&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.11.3%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.11.3].&lt;br /&gt;
 &lt;br /&gt;
==General fixes and improvements==&lt;br /&gt;
* MDL-70176 - Forum Grading Does Not Respect Separate Groups Filter&lt;br /&gt;
* MDL-71121 - Default settings async course backup&lt;br /&gt;
* MDL-49202 - Checking &amp;quot;Hidden&amp;quot; in grade item settings does not hide the item from student, at the same time selecting &amp;quot;Hide&amp;quot; from dropdown on the setup page does&lt;br /&gt;
* MDL-72242 - Missing SVG files in forum posts&lt;br /&gt;
* MDL-70376 - Assignment - Annotated PDF Download issues when page is turned&lt;br /&gt;
* MDL-72312 - PHP 7.2 tests failing in 3.10 &amp;amp; 3.9, caused by buggy php-igbinary extension&lt;br /&gt;
* MDL-71500 - Cannot select a date on the right hand side 3 month mini calendar, after previously selecting one&lt;br /&gt;
* MDL-69451 - moodle_read_slave_trait: restore temptables object when creating rw and ro handles&lt;br /&gt;
* MDL-72033 - User tours: step placement issues if screen too narrow&lt;br /&gt;
* MDL-71973 - Exception thrown when evaluating disabled models from the CLI&lt;br /&gt;
* MDL-70006 - Suspended enrolment will get analytics messages&lt;br /&gt;
* MDL-70165 - Unable to change user role in a new course&lt;br /&gt;
* MDL-70433 - In gradebook titles, ampersand &#039;&amp;amp;&#039; is being displayed as &amp;amp; amp;&lt;br /&gt;
* MDL-71050 - H5P does not use the correct language&lt;br /&gt;
* MDL-72358 - Error exception in content bank when an H5P file doesn&#039;t exist&lt;br /&gt;
* MDL-72265 - Backup code added in MDL-56310 incorrectly checks moodle/role:safeoverride for users who already have moodle/role:override&lt;br /&gt;
* MDL-67833 - Text run over on Lang customization screen&lt;br /&gt;
* MDL-72035 - Course completion report Excel download should include BOM to ensure correct character encoding&lt;br /&gt;
* MDL-71945 - Bulk releasing grades for anonymous submissions pushes them to gradebook&lt;br /&gt;
* MDL-71844 - Navigation breadcrumbs lost when running single task&lt;br /&gt;
* MDL-71487 - Setting filesize settings to huge values breaks settings pages/search&lt;br /&gt;
* MDL-72207 - Webservice mod_assign_get_submission_status doesn&#039;t support &amp;quot;All participants&amp;quot;&lt;br /&gt;
* MDL-71029 - Forum summary report multiplies counts by number of enrollments a user has&lt;br /&gt;
* MDL-72271 - Clicking &amp;quot;Finish Review&amp;quot; after a quiz set to Full screen popup with Javascript security results in a 404 to /mod/quiz/0 if not in a popup window&lt;br /&gt;
* MDL-72325 - sitepolicynotagreed popup appears when trying to start a user tour&lt;br /&gt;
* MDL-72153 - Privacy export of user data doesn&#039;t export description files correctly/triggers debugging&lt;br /&gt;
* MDL-72106 - Error being displayed after deleting calendar subscription&lt;br /&gt;
* MDL-71899 - Improve 3.11 Activity information performance&lt;br /&gt;
&lt;br /&gt;
==Accessibility improvements==&lt;br /&gt;
* MDL-68639 - Atto produces invalid nested unordered (UL) lists&lt;br /&gt;
* MDL-72286 - Atto plugin steals default submit action so enter key in other fields no longer submits the form&lt;br /&gt;
* MDL-71674 - Atto editor&#039;s insert image dialog boxes do not show all error messages&lt;br /&gt;
* MDL-71656 - Add meaningful label to colour items in colour chooser elements&lt;br /&gt;
* MDL-72206 - Insufficient colour contrast in warning messages in environment check&lt;br /&gt;
* MDL-71814 - Atto: File picker – file info panel focus issue&lt;br /&gt;
&lt;br /&gt;
==Security improvements==&lt;br /&gt;
* MDL-72014 - Update grunt and some components to avoid some security reports&lt;br /&gt;
* MDL-72187 - Log visibility change of log stores&lt;br /&gt;
 &lt;br /&gt;
==Security fixes==&lt;br /&gt;
 	&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.11.2 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.11]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.11.3]]&lt;br /&gt;
[[es:Notas de Moodle 3.11.3]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=61200</id>
		<title>Moodle 4.0 developer update</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_4.0_developer_update&amp;diff=61200"/>
		<updated>2021-09-02T08:06:09Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* The core_courseformat subsystem */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 4.0}}This page will highlight the important changes that are coming in Moodle 4.0 for developers. Including how the UX improvements impact custom themes, relevant API changes, and what you can do as developer to prepare for the 4.0 release.&lt;br /&gt;
== UX and theme changes ==&lt;br /&gt;
== Component library ==&lt;br /&gt;
== Navigation ==&lt;br /&gt;
== The core_courseformat subsystem ==&lt;br /&gt;
Most of the logic for rendering and editing a course has been moved to a new subsystem called courseformat. The subsystem is located at &amp;quot;course/format&amp;quot; folder so it includes all the format plugins inside. The methods and modules which are distributes between the course and the course/format folders are now rearranged or refactored to be aligned with the current Moodle coding style. The major affected specifications are:&lt;br /&gt;
&lt;br /&gt;
* Now format plugins must provide a renderer, which is not optional anymore&lt;br /&gt;
* The old base_format which plugins extends is now core_courseformat\base&lt;br /&gt;
* The methods to render a course are now deprecated and moved to output classes&lt;br /&gt;
* The majority of the javascript logic of the course editing is replaced by a new course editor AMD module. The old libraries are still available for third party formats but will eventually replace the previous ones.&lt;br /&gt;
* Gradually, all tests and templates are being moved to the subsystem folder&lt;br /&gt;
&lt;br /&gt;
== API changes ==&lt;br /&gt;
== Behat changes ==&lt;br /&gt;
To make behat tests more readable and easy to maintain, it is recommended to use the most direct steps to get what the test needs. So since MDL-66335 was integrated, and the step was improved in MDL-72179 is highly recommended to use&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
instead of navigating to the activity via&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
Now that [https://docs.moodle.org/dev/Prototypes#Course_creation_improvements Course index] (MDL-71209) is integrated but the project is not stable, these behat steps&lt;br /&gt;
 I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 I follow &amp;quot;Activity name&amp;quot;&lt;br /&gt;
will fail using Boost theme.&lt;br /&gt;
&lt;br /&gt;
The reason for it is that the drawer used in Boost is hiding the course index. So when the test is trying to follow an &amp;quot;Activity name&amp;quot; link, it finds two different links:&lt;br /&gt;
* one in the course index&lt;br /&gt;
* another one in the course main content.&lt;br /&gt;
But the first one, the one in the course index, is hidden by the drawer, and the test fails.&lt;br /&gt;
&lt;br /&gt;
However the recommended behat steps&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page &lt;br /&gt;
or&lt;br /&gt;
 I am on the &amp;quot;Activity name&amp;quot; &amp;quot;[modname] activity&amp;quot; page logged in as &amp;quot;user&amp;quot;&lt;br /&gt;
work &#039;&#039;&#039;fine&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Some of the failing behats are fixed in https://github.com/ferranrecio/moodle/commit/c79d58a50b48aa6891ff1d3ba92a7b0ab2393c88#diff-fdf8b0b1eade3b69eaad038de0ddd7c8dec2be7afa32dc693fb929739a49fa9dR32 - MDL-71209&lt;br /&gt;
&lt;br /&gt;
For example:&lt;br /&gt;
 And I am on the &amp;quot;Test assignment name&amp;quot; &amp;quot;assign activity&amp;quot; page logged in as teacher1&lt;br /&gt;
instead of:&lt;br /&gt;
 When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
 And I am on &amp;quot;Course&amp;quot; course homepage&lt;br /&gt;
 And I follow &amp;quot;Test assignment name&amp;quot;&lt;br /&gt;
== Core plugins review ==&lt;br /&gt;
A few plugins from core Moodle LMS which are no longer or hardly used have been removed and, if appropriate, added to the Moodle plugins directory.&lt;br /&gt;
&lt;br /&gt;
More information about this project, the list of plugins to be removed and the process to follow for keeping them before upgrading to 4.0 can be found in the [[Core plugins review]] page.&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=JavaScript_namespacing_proposal&amp;diff=61123</id>
		<title>JavaScript namespacing proposal</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=JavaScript_namespacing_proposal&amp;diff=61123"/>
		<updated>2021-08-26T11:31:07Z</updated>

		<summary type="html">&lt;p&gt;Fox: New table coding&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{obsolete}}&lt;br /&gt;
The idea of JavaScript namespacing was raised during the developers meeting that occured on Tuesday 29th September 2009 and I think its a fantastic idea, so I wrote this wee proposal and plan to hopefully win people over and get this is in for Moodle 2.0.&lt;br /&gt;
&lt;br /&gt;
Note: This proposal assumes that the patch proposed for MDL-16699 that splits javascript-static into two files and moves JavaScript that is only being used in a single place within Moodle to a file that can be included by the code that uses it.&lt;br /&gt;
&lt;br /&gt;
===Concept===&lt;br /&gt;
The concept is to apply a namespacing scheme to the JavaScript that is used by Moodle core code. By namespacing the JavaScript we can better define the structure of the JavaScript code as well as hopefully make it both more easily accessible and with any luck make it easier to develop JavaScript that is potentially reusable.&lt;br /&gt;
&lt;br /&gt;
===The root namespace===&lt;br /&gt;
After discussing this with the development team it was decided that the core namespace will be &amp;lt;strong&amp;gt;M&amp;lt;/strong&amp;gt;. The original concept was to go with MOODLE however we decided that there was no need to go with the so many characters where one would do, and this fit in with the changes YUI was making in the release of version 3.0 changing their root namespace from &amp;lt;strong&amp;gt;YAHOO&amp;lt;/strong&amp;gt; to &amp;lt;strong&amp;gt;Y&amp;lt;/strong&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Core namespaces===&lt;br /&gt;
The following are namspaces that will be created in order to support the initial conversion to a namespaced JavaScript core.&lt;br /&gt;
; control : JavaScript that creates controls, or structures used throughout Moodle.&lt;br /&gt;
; dom : JavaScript for interacting with the DOM.&lt;br /&gt;
; form : JavaScript for interacting with forms.&lt;br /&gt;
; util : Miscellaneous JavaScript functions.&lt;br /&gt;
; user : JavaScript that is utilised in direct respect to the user.&lt;br /&gt;
&lt;br /&gt;
===Creating new namespaces===&lt;br /&gt;
Ideally additional code (or as it is being converted) should be namespaced directly after M with a name fitting to the PHP code. For modules this would be the module name e.g. M.forum .&lt;br /&gt;
&lt;br /&gt;
===Time estimate===&lt;br /&gt;
I think it would take a day to namespace the JavaScript files, and then a further day or two to convert the function calls and test.&lt;br /&gt;
It is a reasonably simple procedure and with all of the JavaScript clean up that has gone into head already there should be realivily few edge cases left.&lt;br /&gt;
&lt;br /&gt;
===Implementation===&lt;br /&gt;
The implementation of the core namespace and supporting functions to further namespace is reasonably simple, however it would need to be the very first bit of Moodle JavaScript to be executed. This simply means it would be defined and set up within javascript-priority.js which is the first file to be included in the HTML head.&lt;br /&gt;
&lt;br /&gt;
===Conversion of JavaScript files===&lt;br /&gt;
====lib/javascript-static.js====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&#039;80%&#039;&lt;br /&gt;
|-&lt;br /&gt;
! width=&#039;20%&#039; | Declaration &lt;br /&gt;
! Namespaced declaration&lt;br /&gt;
! width=&#039;20%&#039; | Declaration type&lt;br /&gt;
|-&lt;br /&gt;
| block_hider&lt;br /&gt;
| M.util.block_hider&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| checkall&lt;br /&gt;
| M.form.check_all&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| checknone&lt;br /&gt;
| M.form.check_none&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| collapsible_region&lt;br /&gt;
| M.dom.collapsible_region&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| deselect_all_in&lt;br /&gt;
| M.form.deselect_all_in&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| findParentNode&lt;br /&gt;
| M.dom.find_parent&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| fix_column_width&lt;br /&gt;
| M.util.fix_column_width&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| fix_column_widths&lt;br /&gt;
| M.util.fix_column_widths&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| focuscontrol&lt;br /&gt;
| M.form.set_focus&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| frame_breakout&lt;br /&gt;
| M.frame.add_breakout_target&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| init_help_icons&lt;br /&gt;
| M.util.init_help_icons&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| openpopup&lt;br /&gt;
| M.util.window.popup&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| select_all_in&lt;br /&gt;
| M.form.select_all_in&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| submit_form_by_id&lt;br /&gt;
| M.form.submit_form_by_id&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| emoticons_help&lt;br /&gt;
| M.util.emoticons_help&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| old_onload_focus&lt;br /&gt;
| To be depreacted as part of MDL-19740&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====lib/javascript-priority.js====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&#039;80%&#039;&lt;br /&gt;
|-&lt;br /&gt;
! width=&#039;20%&#039; | Declaration &lt;br /&gt;
! Namespaced declaration&lt;br /&gt;
! width=&#039;20%&#039; | Declaration type&lt;br /&gt;
|-&lt;br /&gt;
| build_querystring&lt;br /&gt;
| M.util.build_query_string&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| cancel_scroll_to_end&lt;br /&gt;
| M.util.scroll.cancel_autoscroll&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| close_window&lt;br /&gt;
| M.util.window.close&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| close_window_reload&lt;br /&gt;
| M.util.window.reload_close&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| confirm_dialog&lt;br /&gt;
| M.control.confirmdialog&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| create_UFO_object&lt;br /&gt;
| M.control.ufo.create&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| destroy_item&lt;br /&gt;
| M.dom.element.remove&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| getElementsByClassName&lt;br /&gt;
| Should really be deprecated in favour of YUI equivilant&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| hide_item&lt;br /&gt;
| M.dom.element.hide&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| json_decode&lt;br /&gt;
| M.util.json.decode&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| json_encode&lt;br /&gt;
| M.util.json.encode&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| repeatedly_scroll_t&lt;br /&gt;
| M.util.scroll.autoscroll&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| scroll_to_end&lt;br /&gt;
| M.util.scroll.bottom&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| M.util.scroll.top&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| set_user_preference&lt;br /&gt;
| M.user.set_preference&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| show_item&lt;br /&gt;
| M.dom.element.show&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| stripHTML&lt;br /&gt;
| M.util.strip_html&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| unmaskPassword&lt;br /&gt;
| M.form.unmask_password&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| update_progress_bar&lt;br /&gt;
| M.control.progressbar.update&lt;br /&gt;
| function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====lib/javascript-navigation.js====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&#039;80%&#039;&lt;br /&gt;
|-&lt;br /&gt;
! width=&#039;20%&#039; | Declaration &lt;br /&gt;
! Namespaced declaration&lt;br /&gt;
! width=&#039;20%&#039; | Declaration type&lt;br /&gt;
|-&lt;br /&gt;
| create_shadow&lt;br /&gt;
| M.control.shadow.create&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| move_all_sidetabs_t...&lt;br /&gt;
| M.control.dock.undock_all&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| navigation_tab_panel&lt;br /&gt;
| M.control.dock&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| navigation_tree&lt;br /&gt;
| M.control.tree&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| navigation_tree_branch&lt;br /&gt;
| M.control.tree.branch&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| remove_shadow&lt;br /&gt;
| M.control.shadow.remove&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| setup_new_navtree&lt;br /&gt;
| M.control.tree.init&lt;br /&gt;
| function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====lib/javascript-deprecated.js====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&#039;80%&#039;&lt;br /&gt;
|-&lt;br /&gt;
! width=&#039;20%&#039; | Declaration &lt;br /&gt;
! Namespaced declaration&lt;br /&gt;
! width=&#039;20%&#039; | Declaration type&lt;br /&gt;
|-&lt;br /&gt;
| deprecate&lt;br /&gt;
| M.util.deprecate&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| deprecated_addonload&lt;br /&gt;
| M.util.deprecated.addonload&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| deprecated_confirm_if&lt;br /&gt;
| M.util.deprecated.confirm_if&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| submitFormById&lt;br /&gt;
| M.util.deprecated.submitFormById&lt;br /&gt;
| function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
====lib/form/form.js====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; width=&#039;80%&#039;&lt;br /&gt;
|-&lt;br /&gt;
! width=&#039;20%&#039; | Declaration &lt;br /&gt;
! Namespaced declaration&lt;br /&gt;
! width=&#039;20%&#039; | Declaration type&lt;br /&gt;
|-&lt;br /&gt;
| date_selector_calendar&lt;br /&gt;
| M.form.mforms.date_selector.calendar&lt;br /&gt;
| object&lt;br /&gt;
|-&lt;br /&gt;
| elementShowAdvanced&lt;br /&gt;
| M.form.mforms.show_advanced.show&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| get_form_element_value&lt;br /&gt;
| M.form.mforms.get_element_value&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| init_date_selectors&lt;br /&gt;
| M.form.mforms.date_selector.init&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| lockoptionsall&lt;br /&gt;
| M.form.mforms.lockoptionsall&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| lockoptionsallsetup&lt;br /&gt;
| M.form.mforms.lockoptionsallsetup&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| set_form_element_disabled&lt;br /&gt;
| M.form.mforms.disable_element&lt;br /&gt;
| funciton&lt;br /&gt;
|-&lt;br /&gt;
| showAdvancedInit&lt;br /&gt;
| M.form.mforms.show_advanced.init&lt;br /&gt;
| function&lt;br /&gt;
|-&lt;br /&gt;
| showAdvancedOnClick&lt;br /&gt;
| M.form.mforms.show_advanced.handle_click&lt;br /&gt;
| function&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Resulting namespaced structure===&lt;br /&gt;
*&amp;lt;strong&amp;gt;M&amp;lt;/strong&amp;gt;&lt;br /&gt;
**&amp;lt;strong&amp;gt;control&amp;lt;/strong&amp;gt;&lt;br /&gt;
***&amp;lt;em&amp;gt;confirmdialog&amp;lt;/em&amp;gt;&lt;br /&gt;
***&amp;lt;em&amp;gt;dock&amp;lt;/em&amp;gt;&lt;br /&gt;
****undock_all&lt;br /&gt;
***&amp;lt;em&amp;gt;tree&amp;lt;/em&amp;gt;&lt;br /&gt;
****&amp;lt;em&amp;gt;branch&amp;lt;/em&amp;gt;&lt;br /&gt;
***progressbar&lt;br /&gt;
****update&lt;br /&gt;
***shadow&lt;br /&gt;
****create&lt;br /&gt;
****remove&lt;br /&gt;
***ufo&lt;br /&gt;
****create&lt;br /&gt;
**&amp;lt;strong&amp;gt;dom&amp;lt;/strong&amp;gt;&lt;br /&gt;
***&amp;lt;strong&amp;gt;element&amp;lt;/strong&amp;gt;&lt;br /&gt;
****hide&lt;br /&gt;
****remove&lt;br /&gt;
****show&lt;br /&gt;
***collapsible_region&lt;br /&gt;
***find_parent&lt;br /&gt;
**&amp;lt;strong&amp;gt;form&amp;lt;/strong&amp;gt;&lt;br /&gt;
***&amp;lt;strong&amp;gt;mforms&amp;lt;/strong&amp;gt;&lt;br /&gt;
****&amp;lt;strong&amp;gt;date_selector&amp;lt;/strong&amp;gt;&lt;br /&gt;
*****calendar&lt;br /&gt;
*****init&lt;br /&gt;
****&amp;lt;strong&amp;gt;show_advanced&amp;lt;/strong&amp;gt;&lt;br /&gt;
*****init&lt;br /&gt;
*****handle_click&lt;br /&gt;
*****show&lt;br /&gt;
****get_element_value&lt;br /&gt;
****lockoptionsall&lt;br /&gt;
****lockoptionsallsetup&lt;br /&gt;
****disable_element&lt;br /&gt;
***check_all&lt;br /&gt;
***check_none&lt;br /&gt;
***deselect_all_in&lt;br /&gt;
***set_focus&lt;br /&gt;
***select_all_in&lt;br /&gt;
***submit_form_by_id&lt;br /&gt;
***unmask_password&lt;br /&gt;
**&amp;lt;strong&amp;gt;util&amp;lt;/strong&amp;gt;&lt;br /&gt;
***&amp;lt;strong&amp;gt;deprecated&amp;lt;/strong&amp;gt;&lt;br /&gt;
****addonload&lt;br /&gt;
****confirm_if&lt;br /&gt;
****submitFormById&lt;br /&gt;
***&amp;lt;strong&amp;gt;json&amp;lt;/strong&amp;gt;&lt;br /&gt;
****decode&lt;br /&gt;
****encode&lt;br /&gt;
***&amp;lt;strong&amp;gt;scroll&amp;lt;/strong&amp;gt;&lt;br /&gt;
****autoscroll&lt;br /&gt;
****bottom&lt;br /&gt;
****top&lt;br /&gt;
***&amp;lt;strong&amp;gt;window&amp;lt;/strong&amp;gt;&lt;br /&gt;
****close&lt;br /&gt;
****popup&lt;br /&gt;
****reload_close&lt;br /&gt;
***block_hider&lt;br /&gt;
***fix_column_width&lt;br /&gt;
***fix_column_widths&lt;br /&gt;
***init_help_icons&lt;br /&gt;
***emoticons_help&lt;br /&gt;
***build_query_string&lt;br /&gt;
***strip_html&lt;br /&gt;
***deprecate&lt;br /&gt;
**&amp;lt;strong&amp;gt;user&amp;lt;/strong&amp;gt;&lt;br /&gt;
***set_preference&lt;br /&gt;
&lt;br /&gt;
===Why bother?===&lt;br /&gt;
Because ....&lt;br /&gt;
# It greatly reduces the chances of developers accidentally creating clashing methods, or variables. Not just with core code but more importantly conflicts that may arise between 3rd party extensions.&lt;br /&gt;
# Hopefully make the JavaScript code more usable and obvious by providing better organisation and structure. This will in turn hopefully reduce the number of identical functions that arise.&lt;br /&gt;
# It&#039;s the sort of thing that can only be done when revision of code is necessary and there&#039;s no time like a major release for that.&lt;br /&gt;
# It looks better, more organised.&lt;br /&gt;
&lt;br /&gt;
===Questions===&lt;br /&gt;
To answer a few quick questions about the process:&lt;br /&gt;
&lt;br /&gt;
; How long would it take to namespace the JavaScript : It wouldn&#039;t take very long at all to go through and apply a namespacing scheme to the JavaScript once the structure has been decided upon. Once the JavaScript has been namespaced it would be a simple case of iterating through the files that make up Moodle and converting references to the original JavaScript functions to their namespaced equivalents.&lt;br /&gt;
&lt;br /&gt;
; Does all JavaScript have to be namespaced : No not at all. Initially only the core JavaScript files would be converted. After this it would be up to developers to namespace their code should they choose to.... it would be the perfect opportunity to revise that legacy JavaScript ;)&lt;br /&gt;
&lt;br /&gt;
; What about code that uses the old function calls? : All of the core uses should be converted as part of the task of namespacing however we certainly need to support the old function calls. We will create mapping functions that simply take a call to a non-namespaced function and pass it to its namespaced equivalent.&lt;br /&gt;
&lt;br /&gt;
; Will any of the JavaScript change? : No. A couple of new internal functions will be introduced to support namespacing however the actual JavaScript functions being namespaced will not change. You will still be able to call them as you did before, you will just need to use the namespaced reference.&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.11_release_notes&amp;diff=58693</id>
		<title>Moodle 3.11 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.11_release_notes&amp;diff=58693"/>
		<updated>2021-04-22T10:05:32Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* For administrators */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released - scheduled for 10 May 2021&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.11%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.11].&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from a previous version, please see [[:en:Upgrading|Upgrading]] in the user docs.&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.6 or later&lt;br /&gt;
* PHP version: minimum PHP 7.3.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.10&#039;&#039;. PHP 7.4.x is supported too. [[Moodle and PHP|PHP 8.0 support]] is being implemented (@ MDL-70745) and &#039;&#039;&#039;not ready for production&#039;&#039;&#039; yet.&lt;br /&gt;
* PHP extension &#039;&#039;&#039;sodium&#039;&#039;&#039; is now required.&lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.6  &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.7 &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 10.2.29 &lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2017 (increased since Moodle 3.10)&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 11.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Moodle 3.10 does NOT support Internet Explorer 11.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Safari 7 and below has known compatibility issues with Moodle 3.10.&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://www.whatsmybrowser.org/&lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other highlights==&lt;br /&gt;
&lt;br /&gt;
===For administrators===&lt;br /&gt;
&lt;br /&gt;
* MDL-67748 - Web services configuration is now located in &#039;&#039;Site administration &amp;gt; Server&#039;&#039; section. Tokens management was improved to allow searching and filtering.&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==For developers==&lt;br /&gt;
&lt;br /&gt;
===Web service additions and updates===&lt;br /&gt;
&lt;br /&gt;
* MDL-71169 - All new external functions implementation classes should use &amp;lt;tt&amp;gt;execute&amp;lt;/tt&amp;gt; as the method name, in which case the &amp;lt;tt&amp;gt;methodname&amp;lt;/tt&amp;gt; property should not be specified in db/services.php file&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.10 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.11]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.11]]&lt;br /&gt;
[[es:Notas de Moodle 3.11]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.9.6_release_notes&amp;diff=58589</id>
		<title>Moodle 3.9.6 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.9.6_release_notes&amp;diff=58589"/>
		<updated>2021-03-25T07:59:59Z</updated>

		<summary type="html">&lt;p&gt;Fox: Corrected French link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 25 March 2021&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.9.6%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.9.6].&lt;br /&gt;
  &lt;br /&gt;
===Regression fix===&lt;br /&gt;
 &lt;br /&gt;
* MDL-71182 - Revert latest calendar/data request changes (revert MDL-67494)&lt;br /&gt;
&lt;br /&gt;
==Other fixes==&lt;br /&gt;
&lt;br /&gt;
* MDL-66025 - It&#039;s possible to send an empty message to course participants&lt;br /&gt;
&lt;br /&gt;
==Accessibility improvements==&lt;br /&gt;
&lt;br /&gt;
* MDL-70992 - Folder: Unnecessary tab stops to the left of files&lt;br /&gt;
&lt;br /&gt;
==Security improvements==&lt;br /&gt;
&lt;br /&gt;
* MDL-71068 - Usernames or emails can be enumerated under certain conditions with $CFG-&amp;gt;protectusernames on&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Moodle 3.9.5 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.9]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.9.6]]&lt;br /&gt;
[[es:Notas de Moodle 3.9.6]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.10.1_release_notes&amp;diff=58226</id>
		<title>Moodle 3.10.1 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.10.1_release_notes&amp;diff=58226"/>
		<updated>2021-01-22T08:25:26Z</updated>

		<summary type="html">&lt;p&gt;Fox: Warning like for Moodle 3.9.4&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: 18 January 2021&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.10.1%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.10.1].&lt;br /&gt;
&lt;br /&gt;
==Warning - courses with many sections==&lt;br /&gt;
If you use a custom course format, and your courses need to have a large number of sections (more than 52),  for this release you may need to implement the method get_max_sections() in your custom course format&#039;s lib.php file, to set a higher limit than the default.  The default comes from get_max_sections() in course/format/lib.php - you can copy this method into your course format&#039;s lib file and use whatever maximum you need.&lt;br /&gt;
&lt;br /&gt;
==General fixes and improvements==&lt;br /&gt;
* MDL-54907 - Automatically submitted quiz attempts: finish time is set to when cron ran, not when the attempt ended&lt;br /&gt;
* MDL-69964 - The &amp;quot;Select all X users&amp;quot; button doesn&#039;t activate the drop-down menu in Participants Page&lt;br /&gt;
* MDL-68896 - SCORM error in Chrome because of &amp;quot;XHR in page dismissal&amp;quot; policy change&lt;br /&gt;
* MDL-67623 - Course overview (my courses block) pagination is broken beyond the second page&lt;br /&gt;
* MDL-56119 - Rubric display layout issue, after students feedback is released&lt;br /&gt;
* MDL-50955 - Lesson module error on save - Cannot find grade item for &#039;lesson&#039;&lt;br /&gt;
* MDL-65941 - Redis server issues break cache configuration page&lt;br /&gt;
* MDL-70285 - The MDL-69687 upgrade step kills large databases&lt;br /&gt;
* MDL-69526 - Custom field values in course overview block follow incorrect order&lt;br /&gt;
* MDL-65852 - Non-editing teacher should be able to download course participants list&lt;br /&gt;
* MDL-70265 - Reduce the number of phpunit runs in core&#039;s .travis.yml&lt;br /&gt;
* MDL-70386 - Illegible css coloring of correct/incorrect div&lt;br /&gt;
* MDL-69930 - Duplication items in drag-onto-image question&lt;br /&gt;
* MDL-70276 - Add support for github actions to moodle.git&lt;br /&gt;
* MDL-70355 - Multilang Filters not applied to Calendar block&lt;br /&gt;
* MDL-70063 - [Youtube Plugin] Selecting a category results in &amp;lt;data could not be obtained&amp;gt; error&lt;br /&gt;
* MDL-67513 - View conversation link does not work when grading in full screen mode&lt;br /&gt;
* MDL-70558 - Available language packs unsorted, difficult to locate&lt;br /&gt;
* MDL-69868 - H5P corrupts USER object, causing forum error&lt;br /&gt;
* MDL-70426 - Drag-drop markers questions: infinite markers keep duplicating&lt;br /&gt;
* MDL-70065 - Quiz add questions from question bank: problem with paging &amp;amp; show all&lt;br /&gt;
* MDL-62707 - codingerror in Global Search when &amp;quot;search within enrolled courses only&amp;quot; is set&lt;br /&gt;
* MDL-70430 - OAuth2 system account&#039;s refresh token does not get updated due to a typo&lt;br /&gt;
* MDL-70148 - Write new keyboard steps for Behat&lt;br /&gt;
* MDL-69955 - Question type Drag and Drop: drop zone disappear in special case&lt;br /&gt;
* MDL-70320 - Incorrect HTML escaping on the override permissions screen&lt;br /&gt;
* MDL-70261 - Upload Courses tool breaks on locked custom fields&lt;br /&gt;
* MDL-70153 - Qtype_essay file-size limit: it says &amp;quot;0 bytes&amp;quot; for students when &amp;quot;Site upload limit&amp;quot; is set&lt;br /&gt;
* MDL-70436 - On mobile, the Quiz confirmation modal has it&#039;s close button cut off&lt;br /&gt;
* MDL-70373 - Atto HTML editor lacks border outside Moodle forms (e.g. Essay questions)&lt;br /&gt;
* MDL-70374 - Layout of multiple choice questions not well aligned&lt;br /&gt;
* MDL-70520 - Moodle upgrade resets  scheduled tasks lastruntime&lt;br /&gt;
* MDL-70117 - PDF dataformat export: content can overflow when page headers are involved&lt;br /&gt;
* MDL-70072 - Date in message system  (always in Gregorian)&lt;br /&gt;
* MDL-70237 - Payment modal breaks if there is html in a gateway description&lt;br /&gt;
* MDL-70248 - Drag and Drop onto images: Drop zones have UI issue in Editing form&lt;br /&gt;
* MDL-67636 - Locking grade category exposes hidden item grades on user report&lt;br /&gt;
* MDL-70352 - Modal forms stay on the screen if you have multiple modals on one page&lt;br /&gt;
* MDL-70580 - Privacy export tree navigation non-functional since MDL-69559&lt;br /&gt;
* MDL-70567 - Task logs page doesn&#039;t respect result filter when moving through the pagination&lt;br /&gt;
* MDL-70009 - Course with H5P element in content bank can not be deleted by Manager/Teacher role (with appropriate rights)&lt;br /&gt;
&lt;br /&gt;
==Accessibility improvements==&lt;br /&gt;
* MDL-69841 - Edit Quiz, click on help icon under review options group will check / uncheck the checkbox&lt;br /&gt;
* MDL-69422 - HTML validation and accessibility problems on database export page&lt;br /&gt;
* MDL-69301 - Focus order in tabs&lt;br /&gt;
* MDL-70094 - Question preview: Technical info section expands if you click the help icon there&lt;br /&gt;
 &lt;br /&gt;
==Security improvements==&lt;br /&gt;
* MDL-69877 - Set up a security.txt file in Moodle LMS&lt;br /&gt;
&lt;br /&gt;
==Security fixes==&lt;br /&gt;
 	&lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.10 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.10]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.10.1]]&lt;br /&gt;
[[es:Notas de Moodle 3.10.1]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Releases&amp;diff=57867</id>
		<title>Releases</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Releases&amp;diff=57867"/>
		<updated>2020-09-15T14:20:20Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* Moodle 3.8 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page lists all official releases of Moodle, grouped by branch in reverse chronological order.&lt;br /&gt;
&lt;br /&gt;
==Version support==&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.6 onwards, the end of support, both general and security, happens the second Monday of May and November, observing the 12, 18... month periods, no matter if the major release was delayed or not.&lt;br /&gt;
&lt;br /&gt;
The most recent [https://en.wikipedia.org/wiki/Long-term_support long-term support release (LTS)] version is Moodle 3.9.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1px solid #dee2e6;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: rgba(0, 0, 0, 0.05);&amp;quot; | Version&lt;br /&gt;
! style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: rgba(0, 0, 0, 0.05);&amp;quot; | Release status&lt;br /&gt;
! style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: rgba(0, 0, 0, 0.05);&amp;quot; | Initial release&lt;br /&gt;
! style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:rgba(0, 0, 0, 0.05);&amp;quot; | General support ends&lt;br /&gt;
! style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: rgba(0, 0, 0, 0.05);&amp;quot; | Security support ends&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 3.5 (LTS)&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#239cae; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Current security&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 17 May 2018&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 13 May 2019&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 10 May 2021&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 3.7&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#239cae; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Current security&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 20 May 2019&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 11 May 2020&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 9 November 2020&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 3.8&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#f98012; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Current stable&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 18 November 2019&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 9 November 2020&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 10 May 2021&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 3.9 (LTS)&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#f98012; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Current stable&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 15 June 2020&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 10 May 2021&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | 8 May 2023&lt;br /&gt;
|}&lt;br /&gt;
[[Image:releasescurrent.png|alt=Release graph]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;b&amp;gt;Release graph key:&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1px solid #dee2e6;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#f98012; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Current stables&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: rgba(0, 0, 0, 0.05);&amp;quot; | Currently supported stable releases.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#239cae; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Current security&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | Current release of versions still receiving security-only updates.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#9cbd50; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Future stables&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: rgba(0, 0, 0, 0.05);&amp;quot; | Future point releases receiving bug fixes, as well as security updates.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#316d5e; color:white; adding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Future security&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | Future point releases receiving security-only updates.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#686566; color:white; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Past stables&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: rgba(0, 0, 0, 0.05);&amp;quot; | Previously released versions containing bug fixes, as well as security updates. Updating to a currently supported version is recommended.&lt;br /&gt;
|-&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color:#282828; color:white; padding: .3rem 0.5rem 0.3rem 0.5rem;&amp;quot; | Past security&lt;br /&gt;
| style=&amp;quot;vertical-align: top; border-top: 1px solid #dee2e6; background-color: #FFFFFF&amp;quot; | Previously released versions containing security updates only. Updating to a currently supported version is recommended.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==General release calendar==&lt;br /&gt;
&lt;br /&gt;
These are the target dates for releases. These dates may vary slightly due to unforeseen circumstances.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Release type&lt;br /&gt;
! Frequency&lt;br /&gt;
! Months&lt;br /&gt;
|-&lt;br /&gt;
| [[Process#Major_release_cycles|Major]] (eg. 3.x)&lt;br /&gt;
| 6 monthly&lt;br /&gt;
| Second Monday of May and November&lt;br /&gt;
|-&lt;br /&gt;
| [[Process#Stable_maintenance_cycles|Minor]] (Point) (eg. 3.x.y)&lt;br /&gt;
| 2 monthly&lt;br /&gt;
| Second Monday of July, September, November, January, March and May&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All releases are preceded by a one week warning. Upcoming release dates can be found in the [https://www.google.com/calendar/ical/moodle.com_p4c2oe7hsb77ltaro5qtihb5d4%40group.calendar.google.com/public/basic.ics Moodle development calendar] (Note, this is an iCAL link that will try to add the dates to your personal calendar. If you just want to browse the dates online, use [https://calendar.google.com/calendar/embed?src=moodle.com_p4c2oe7hsb77ltaro5qtihb5d4@group.calendar.google.com&amp;amp;pli=1 this link].).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.9 (LTS)==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.9&lt;br /&gt;
| 15 June 2020&lt;br /&gt;
| 2020061500&lt;br /&gt;
| [[Moodle 3.9 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/39/en/Upgrading Upgrading to 3.9]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.9.1&lt;br /&gt;
| 13 July 2020&lt;br /&gt;
| 2020061501&lt;br /&gt;
| [[Moodle 3.9.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.9.2&lt;br /&gt;
| 14 September 2020&lt;br /&gt;
| 2020061502&lt;br /&gt;
| [[Moodle 3.9.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.9.x will end 10 May 2021 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.9.x will end 8 May 2023 (36 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.8==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.8&lt;br /&gt;
| 18 November 2019&lt;br /&gt;
| 2019111800&lt;br /&gt;
| [[Moodle 3.8 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/38/en/Upgrading Upgrading to 3.8]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.8.1&lt;br /&gt;
| 13 January 2020&lt;br /&gt;
| 2019111801&lt;br /&gt;
| [[Moodle 3.8.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.8.2&lt;br /&gt;
| 9 March 2020&lt;br /&gt;
| 2019111802&lt;br /&gt;
| [[Moodle 3.8.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.8.3&lt;br /&gt;
| 11 May 2020&lt;br /&gt;
| 2019111803&lt;br /&gt;
| [[Moodle 3.8.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.8.4&lt;br /&gt;
| 13 July 2020&lt;br /&gt;
| 2019111804&lt;br /&gt;
| [[Moodle 3.8.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.8.5&lt;br /&gt;
| 14 September 2020&lt;br /&gt;
| 2019111805&lt;br /&gt;
| [[Moodle 3.8.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.8.x will end 9 November 2020 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.8.x will end 10 May 2021 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.7==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7&lt;br /&gt;
| 20 May 2019&lt;br /&gt;
| 2019052000&lt;br /&gt;
| [[Moodle 3.7 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/37/en/Upgrading Upgrading to 3.7]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.1&lt;br /&gt;
| 8 July 2019&lt;br /&gt;
| 2019052001&lt;br /&gt;
| [[Moodle 3.7.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.2&lt;br /&gt;
| 9 September 2019&lt;br /&gt;
| 2019052002&lt;br /&gt;
| [[Moodle 3.7.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.3&lt;br /&gt;
| 11 November 2019&lt;br /&gt;
| 2019052003&lt;br /&gt;
| [[Moodle 3.7.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.4&lt;br /&gt;
| 13 January 2020&lt;br /&gt;
| 2019052004&lt;br /&gt;
| [[Moodle 3.7.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.5&lt;br /&gt;
| 9 March 2020&lt;br /&gt;
| 2019052005&lt;br /&gt;
| [[Moodle 3.7.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.6&lt;br /&gt;
| 11 May 2020&lt;br /&gt;
| 2019052006&lt;br /&gt;
| [[Moodle 3.7.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.7&lt;br /&gt;
| 13 July 2020&lt;br /&gt;
| 2019052007&lt;br /&gt;
| [[Moodle 3.7.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.7.8&lt;br /&gt;
| 14 September 2020&lt;br /&gt;
| 2019052008&lt;br /&gt;
| [[Moodle 3.7.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.7.x ended 11 May 2020 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.7.x will end 9 November 2020 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.6==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6&lt;br /&gt;
| 3 December 2018&lt;br /&gt;
| 2018120300&lt;br /&gt;
| [[Moodle 3.6 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/36/en/Upgrading Upgrading to 3.6]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.1&lt;br /&gt;
| 5 December 2018&lt;br /&gt;
| 2018120301&lt;br /&gt;
| [[Moodle 3.6.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.2&lt;br /&gt;
| 14 January 2019&lt;br /&gt;
| 2018120302&lt;br /&gt;
| [[Moodle 3.6.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.3&lt;br /&gt;
| 11 March 2019&lt;br /&gt;
| 2018120303&lt;br /&gt;
| [[Moodle 3.6.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.4&lt;br /&gt;
| 13 May 2019&lt;br /&gt;
| 2018120304&lt;br /&gt;
| [[Moodle 3.6.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.5&lt;br /&gt;
| 8th July 2019&lt;br /&gt;
| 2018120305&lt;br /&gt;
| [[Moodle 3.6.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.6&lt;br /&gt;
| 9th September 2019&lt;br /&gt;
| 2018120306&lt;br /&gt;
| [[Moodle 3.6.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.7&lt;br /&gt;
| 11th November 2019&lt;br /&gt;
| 2018120307&lt;br /&gt;
| [[Moodle 3.6.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.8&lt;br /&gt;
| 13th January 2020&lt;br /&gt;
| 2018120308&lt;br /&gt;
| [[Moodle 3.6.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.9&lt;br /&gt;
| 9th March 2020&lt;br /&gt;
| 2018120309&lt;br /&gt;
| [[Moodle 3.6.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.10&lt;br /&gt;
| 11th May 2020&lt;br /&gt;
| 2018120310&lt;br /&gt;
| [[Moodle 3.6.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.6.x ended 11 November 2019 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.6.x ended 11 May 2020 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.5 (LTS)==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2018051700&lt;br /&gt;
| [[Moodle 3.5 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/35/en/Upgrading Upgrading to 3.5]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.1&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2018051701&lt;br /&gt;
| [[Moodle 3.5.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.2&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2018051702&lt;br /&gt;
| [[Moodle 3.5.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.3&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2018051703&lt;br /&gt;
| [[Moodle 3.5.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.4&lt;br /&gt;
| 14 January 2019&lt;br /&gt;
| 2018051704&lt;br /&gt;
| [[Moodle 3.5.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.5&lt;br /&gt;
| 11 March 2019&lt;br /&gt;
| 2018051705&lt;br /&gt;
| [[Moodle 3.5.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.6&lt;br /&gt;
| 13 May 2019&lt;br /&gt;
| 2018051706&lt;br /&gt;
| [[Moodle 3.5.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.7&lt;br /&gt;
| 8 July 2019&lt;br /&gt;
| 2018051707&lt;br /&gt;
| [[Moodle 3.5.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.8&lt;br /&gt;
| 9 September 2019&lt;br /&gt;
| 2018051708&lt;br /&gt;
| [[Moodle 3.5.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.9&lt;br /&gt;
| 11 November 2019&lt;br /&gt;
| 2018051709&lt;br /&gt;
| [[Moodle 3.5.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.10&lt;br /&gt;
| 13 January 2020&lt;br /&gt;
| 2018051710&lt;br /&gt;
| [[Moodle 3.5.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.11&lt;br /&gt;
| 9 March 2020&lt;br /&gt;
| 2018051711&lt;br /&gt;
| [[Moodle 3.5.11 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.12&lt;br /&gt;
| 11 May 2020&lt;br /&gt;
| 2018051712&lt;br /&gt;
| [[Moodle 3.5.12 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.13&lt;br /&gt;
| 13 July 2020&lt;br /&gt;
| 2018051713&lt;br /&gt;
| [[Moodle 3.5.13 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.14&lt;br /&gt;
| 14 September 2020&lt;br /&gt;
| 2018051714&lt;br /&gt;
| [[Moodle 3.5.14 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.5.x ended May 2019 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.5.x will end 10 May 2021 (36 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.4==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2017111300&lt;br /&gt;
| [[Moodle 3.4 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/34/en/Upgrading Upgrading to 3.4]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.1&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2017111301&lt;br /&gt;
| [[Moodle 3.4.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.2&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2017111302&lt;br /&gt;
| [[Moodle 3.4.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.3&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2017111303&lt;br /&gt;
| [[Moodle 3.4.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.4&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2017111304&lt;br /&gt;
| [[Moodle 3.4.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.5&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2017111305&lt;br /&gt;
| [[Moodle 3.4.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.6&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2017111306&lt;br /&gt;
| [[Moodle 3.4.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.7&lt;br /&gt;
| 14 January 2019&lt;br /&gt;
| 2017111307&lt;br /&gt;
| [[Moodle 3.4.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.8&lt;br /&gt;
| 11 March 2019&lt;br /&gt;
| 2017111308&lt;br /&gt;
| [[Moodle 3.4.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.9&lt;br /&gt;
| 13 May 2019&lt;br /&gt;
| 2017111309&lt;br /&gt;
| [[Moodle 3.4.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.4.x ended 12 November 2018 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.4.x ended 13 May 2019 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.3==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3&lt;br /&gt;
| 15 May 2017&lt;br /&gt;
| 2017051500&lt;br /&gt;
| [[Moodle 3.3 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/33/en/Upgrading Upgrading to 3.3]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.1&lt;br /&gt;
| 10 July 2017&lt;br /&gt;
| 2017051501&lt;br /&gt;
| [[Moodle 3.3.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.2&lt;br /&gt;
| 11 September 2017&lt;br /&gt;
| 2017051502&lt;br /&gt;
| [[Moodle 3.3.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.3&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2017051503&lt;br /&gt;
| [[Moodle 3.3.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.4&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2017051504&lt;br /&gt;
| [[Moodle 3.3.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.5&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2017051505&lt;br /&gt;
| [[Moodle 3.3.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.6&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2017051506&lt;br /&gt;
| [[Moodle 3.3.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.7&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2017051507&lt;br /&gt;
| [[Moodle 3.3.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.8&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2017051508&lt;br /&gt;
| [[Moodle 3.3.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.9&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2017051509&lt;br /&gt;
| [[Moodle 3.3.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.3.x ended 17 May 2018 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.3.x ended 12 November 2018 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.2==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2&lt;br /&gt;
| 5 December 2016&lt;br /&gt;
| 2016120500&lt;br /&gt;
| [[Moodle 3.2 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/32/en/Upgrading Upgrading to 3.2]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.1&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2016120501&lt;br /&gt;
| [[Moodle 3.2.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.2&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2016120502&lt;br /&gt;
| [[Moodle 3.2.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.3&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2016120503&lt;br /&gt;
| [[Moodle 3.2.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.4&lt;br /&gt;
| 10 July 2017&lt;br /&gt;
| 2016120504&lt;br /&gt;
| [[Moodle 3.2.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.5&lt;br /&gt;
| 11 September 2017&lt;br /&gt;
| 2016120505&lt;br /&gt;
| [[Moodle 3.2.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.6&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2016120506&lt;br /&gt;
| [[Moodle 3.2.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.7&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2016120507&lt;br /&gt;
| [[Moodle 3.2.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.8&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2016120508&lt;br /&gt;
| [[Moodle 3.2.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.9&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2016120509&lt;br /&gt;
| [[Moodle 3.2.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.2.x ended 13 November 2017 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.2.x ended 17 May 2018 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.1 (LTS)==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1&lt;br /&gt;
| 23 May 2016&lt;br /&gt;
| 2016052300&lt;br /&gt;
| [[Moodle 3.1 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/31/en/Upgrading Upgrading to 3.1]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.1&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2016052301&lt;br /&gt;
| [[Moodle 3.1.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.2&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2016052302&lt;br /&gt;
| [[Moodle 3.1.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.3&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2016052303&lt;br /&gt;
| [[Moodle 3.1.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.4&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2016052304&lt;br /&gt;
| [[Moodle 3.1.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.5&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2016052305&lt;br /&gt;
| [[Moodle 3.1.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.6&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2016052306&lt;br /&gt;
| [[Moodle 3.1.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.7&lt;br /&gt;
| 10 July 2017&lt;br /&gt;
| 2016052307&lt;br /&gt;
| [[Moodle 3.1.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.8&lt;br /&gt;
| 11 September 2017&lt;br /&gt;
| 2016052308&lt;br /&gt;
| [[Moodle 3.1.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.9&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2016052309&lt;br /&gt;
| [[Moodle 3.1.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.10&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2016052310&lt;br /&gt;
| [[Moodle 3.1.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.11&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2016052311&lt;br /&gt;
| [[Moodle 3.1.11 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.12&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2016052312&lt;br /&gt;
| [[Moodle 3.1.12 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.13&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2016052313&lt;br /&gt;
| [[Moodle 3.1.13 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.14&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2016052314&lt;br /&gt;
| [[Moodle 3.1.14 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.15&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2016052315&lt;br /&gt;
| [[Moodle 3.1.15 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.16&lt;br /&gt;
| 14 January 2019&lt;br /&gt;
| 2016052316&lt;br /&gt;
| [[Moodle 3.1.16 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.17&lt;br /&gt;
| 11 March 2019&lt;br /&gt;
| 2016052317&lt;br /&gt;
| [[Moodle 3.1.17 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.18&lt;br /&gt;
| 13 May 2019&lt;br /&gt;
| 2016052318&lt;br /&gt;
| [[Moodle 3.1.18 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.1.x ended 8 May 2017 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.1.x ended 13 May 2019 (36 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.0==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0&lt;br /&gt;
| 16 November 2015&lt;br /&gt;
| 2015111600&lt;br /&gt;
| [[Moodle 3.0 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/30/en/Upgrading Upgrading to 3.0]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.1&lt;br /&gt;
| 21 December 2015&lt;br /&gt;
| 2015111601&lt;br /&gt;
| [[Moodle 3.0.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.2&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2015111602&lt;br /&gt;
| [[Moodle 3.0.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.3&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2015111603&lt;br /&gt;
| [[Moodle 3.0.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.4&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2015111604&lt;br /&gt;
| [[Moodle 3.0.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.5&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2015111605&lt;br /&gt;
| [[Moodle 3.0.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.6&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2015111606&lt;br /&gt;
| [[Moodle 3.0.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.7&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2015111607&lt;br /&gt;
| [[Moodle 3.0.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.8&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2015111608&lt;br /&gt;
| [[Moodle 3.0.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.9&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2015111609&lt;br /&gt;
| [[Moodle 3.0.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.10&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2015111610&lt;br /&gt;
| [[Moodle 3.0.10 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.0.x ended 14 November 2016 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.0.x ended 8 May 2017 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.9==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2015051100&lt;br /&gt;
| [[Moodle 2.9 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/29/en/Upgrading_to_Moodle_2.9 Upgrading to 2.9]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.1&lt;br /&gt;
| 6 July 2015&lt;br /&gt;
| 2015051101&lt;br /&gt;
| [[Moodle 2.9.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.2&lt;br /&gt;
| 14 September 2015&lt;br /&gt;
| 2015051102&lt;br /&gt;
| [[Moodle 2.9.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.3&lt;br /&gt;
| 9 November 2015&lt;br /&gt;
| 2015051103&lt;br /&gt;
| [[Moodle 2.9.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.4&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2015051104&lt;br /&gt;
| [[Moodle 2.9.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.5&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2015051105&lt;br /&gt;
| [[Moodle 2.9.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.6&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2015051106&lt;br /&gt;
| [[Moodle 2.9.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.7&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2015051107&lt;br /&gt;
| [[Moodle 2.9.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.8&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2015051108&lt;br /&gt;
| [[Moodle 2.9.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.9&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2015051109&lt;br /&gt;
| [[Moodle 2.9.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.9.x ended 9 May 2016 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.9.x ended 14 November 2016 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.8==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2014111000&lt;br /&gt;
| [[Moodle 2.8 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/28/en/Upgrading_to_Moodle_2.8 Upgrading to 2.8]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.1&lt;br /&gt;
| 13 November 2014&lt;br /&gt;
| 2014111001&lt;br /&gt;
| [[Moodle 2.8.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.2&lt;br /&gt;
| 12 January 2015&lt;br /&gt;
| 2014111002&lt;br /&gt;
| [[Moodle 2.8.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.3&lt;br /&gt;
| 2 February 2015&lt;br /&gt;
| 2014111003&lt;br /&gt;
| [[Moodle 2.8.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.4&lt;br /&gt;
| 9 March 2015&lt;br /&gt;
| 2014111004&lt;br /&gt;
| [[Moodle 2.8.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.5&lt;br /&gt;
| 10 March 2015&lt;br /&gt;
| 2014111005&lt;br /&gt;
| [[Moodle 2.8.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.6&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2014111006&lt;br /&gt;
| [[Moodle 2.8.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.7&lt;br /&gt;
| 6 July 2015&lt;br /&gt;
| 2014111007&lt;br /&gt;
| [[Moodle 2.8.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.8&lt;br /&gt;
| 14 September 2015&lt;br /&gt;
| 2014111008&lt;br /&gt;
| [[Moodle 2.8.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.9&lt;br /&gt;
| 9 November 2015&lt;br /&gt;
| 2014111009&lt;br /&gt;
| [[Moodle 2.8.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.10&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2014111010&lt;br /&gt;
| [[Moodle 2.8.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.11&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2014111011&lt;br /&gt;
| [[Moodle 2.8.11 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.12&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2014111012&lt;br /&gt;
| [[Moodle 2.8.12 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.7 (LTS)==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2014051200&lt;br /&gt;
| [[Moodle 2.7 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/27/en/Upgrading_to_Moodle_2.7 Upgrading to 2.7]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.1&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2014051201&lt;br /&gt;
| [[Moodle 2.7.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.2&lt;br /&gt;
| 8 September 2014&lt;br /&gt;
| 2014051202&lt;br /&gt;
| [[Moodle 2.7.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.3&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2014051203&lt;br /&gt;
| [[Moodle 2.7.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.4&lt;br /&gt;
| 12 January 2015&lt;br /&gt;
| 2014051204&lt;br /&gt;
| [[Moodle 2.7.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.5&lt;br /&gt;
| 2 February 2015&lt;br /&gt;
| 2014051205&lt;br /&gt;
| [[Moodle 2.7.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.6&lt;br /&gt;
| 9 March 2015&lt;br /&gt;
| 2014051206&lt;br /&gt;
| [[Moodle 2.7.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.7&lt;br /&gt;
| 10 March 2015&lt;br /&gt;
| 2014051207&lt;br /&gt;
| [[Moodle 2.7.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.8&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2014051208&lt;br /&gt;
| [[Moodle 2.7.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.9&lt;br /&gt;
| 6 July 2015&lt;br /&gt;
| 2014051209&lt;br /&gt;
| [[Moodle 2.7.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.10&lt;br /&gt;
| 14 September 2015&lt;br /&gt;
| 2014051210&lt;br /&gt;
| [[Moodle 2.7.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.11&lt;br /&gt;
| 9 November 2015&lt;br /&gt;
| 2014051211&lt;br /&gt;
| [[Moodle 2.7.11 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.12&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2014051212&lt;br /&gt;
| [[Moodle 2.7.12 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.13&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2014051213&lt;br /&gt;
| [[Moodle 2.7.13 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.14&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2014051214&lt;br /&gt;
| [[Moodle 2.7.14 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.15&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2014051215&lt;br /&gt;
| [[Moodle 2.7.15 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.16&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2014051216&lt;br /&gt;
| [[Moodle 2.7.16 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.17&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2014051217&lt;br /&gt;
| [[Moodle 2.7.17 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.18&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2014051218&lt;br /&gt;
| [[Moodle 2.7.18 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.19&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2014051219&lt;br /&gt;
| [[Moodle 2.7.19 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.20&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2014051220&lt;br /&gt;
| [[Moodle 2.7.20 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.7.x ended 11 May 2015 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.7.x ended 8 May 2017 (36 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.6==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6&lt;br /&gt;
| 18 November 2013&lt;br /&gt;
| 2013111800&lt;br /&gt;
| [[Moodle 2.6 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/26/en/Upgrading_to_Moodle_2.6 Upgrading to 2.6]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.1&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2013111801&lt;br /&gt;
| [[Moodle 2.6.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.2&lt;br /&gt;
| 10 March 2014&lt;br /&gt;
| 2013111802&lt;br /&gt;
| [[Moodle 2.6.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.3&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2013111803&lt;br /&gt;
| [[Moodle 2.6.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.4&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2013111804&lt;br /&gt;
| [[Moodle 2.6.4 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.5&lt;br /&gt;
| 8 September 2014&lt;br /&gt;
| 2013111805&lt;br /&gt;
| [[Moodle 2.6.5 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.6&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2013111806&lt;br /&gt;
| [[Moodle 2.6.6 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.7&lt;br /&gt;
| 12 January 2015&lt;br /&gt;
| 2013111807&lt;br /&gt;
| [[Moodle 2.6.7 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.8&lt;br /&gt;
| 2 February 2015&lt;br /&gt;
| 2013111808&lt;br /&gt;
| [[Moodle 2.6.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.9&lt;br /&gt;
| 9 March 2015&lt;br /&gt;
| 2013111809&lt;br /&gt;
| [[Moodle 2.6.9 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.10&lt;br /&gt;
| 10 March 2015&lt;br /&gt;
| 2013111810&lt;br /&gt;
| [[Moodle 2.6.10 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.11&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2013111811&lt;br /&gt;
| [[Moodle 2.6.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.6.x ended 10 November 2014 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.6.x ended 11 May 2015 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.5==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2013051400&lt;br /&gt;
| [[Moodle 2.5 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/25/en/Upgrading_to_Moodle_2.5 Upgrading to 2.5]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.1&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2013051401&lt;br /&gt;
| [[Moodle 2.5.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.2&lt;br /&gt;
| 9 September 2013&lt;br /&gt;
| 2013051402&lt;br /&gt;
| [[Moodle 2.5.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.3&lt;br /&gt;
| 11 November 2013&lt;br /&gt;
| 2013051403&lt;br /&gt;
| [[Moodle 2.5.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.4&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2013051404&lt;br /&gt;
| [[Moodle 2.5.4 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.5&lt;br /&gt;
| 10 March 2014&lt;br /&gt;
| 2013051405&lt;br /&gt;
| [[Moodle 2.5.5 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.6&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2013051406&lt;br /&gt;
| [[Moodle 2.5.6 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.7&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2013051407&lt;br /&gt;
| [[Moodle 2.5.7 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.8&lt;br /&gt;
| 8 September 2014&lt;br /&gt;
| 2013051408&lt;br /&gt;
| [[Moodle 2.5.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.9&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2013051409&lt;br /&gt;
| [[Moodle 2.5.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.5.x ended May 2014 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.5.x ended 10 November 2014 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.4==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4&lt;br /&gt;
| 3 December 2012&lt;br /&gt;
| 2012120300&lt;br /&gt;
| [[Moodle 2.4 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/24/en/Upgrading_to_Moodle_2.4 Upgrading to 2.4]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.1&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 2012120301&lt;br /&gt;
| [[Moodle 2.4.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.2&lt;br /&gt;
| 11 March 2013&lt;br /&gt;
| 2012120302&lt;br /&gt;
| [[Moodle 2.4.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.3&lt;br /&gt;
| 18 March 2013&lt;br /&gt;
| 2012120303&lt;br /&gt;
| [[Moodle 2.4.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.4&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2012120304&lt;br /&gt;
| [[Moodle 2.4.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.5&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2012120305&lt;br /&gt;
| [[Moodle 2.4.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.6&lt;br /&gt;
| 9 September 2013&lt;br /&gt;
| 2012120306&lt;br /&gt;
| [[Moodle 2.4.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.7&lt;br /&gt;
| 11 November 2013&lt;br /&gt;
| 2012120307&lt;br /&gt;
| [[Moodle 2.4.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.8&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2012120308&lt;br /&gt;
| [[Moodle 2.4.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.9&lt;br /&gt;
| 10 March 2014&lt;br /&gt;
| 2012120309&lt;br /&gt;
| [[Moodle 2.4.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.10&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2012120310&lt;br /&gt;
| [[Moodle 2.4.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.11&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2012120311&lt;br /&gt;
| [[Moodle 2.4.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.4.x ended December 2013 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.4.x ended June 2014 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.3==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3&lt;br /&gt;
| 25 June 2012&lt;br /&gt;
| 2012062500&lt;br /&gt;
| [[Moodle 2.3 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/23/en/Upgrading_to_Moodle_2.3 Upgrading to 2.3]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.1&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2012062501&lt;br /&gt;
| [[Moodle 2.3.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.2&lt;br /&gt;
| 10 September 2012&lt;br /&gt;
| 2012062502&lt;br /&gt;
| [[Moodle 2.3.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.3&lt;br /&gt;
| 12 November 2012&lt;br /&gt;
| 2012062503&lt;br /&gt;
| [[Moodle 2.3.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.4&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 2012062504&lt;br /&gt;
| [[Moodle 2.3.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.5&lt;br /&gt;
| 11 March 2013&lt;br /&gt;
| 2012062505&lt;br /&gt;
| [[Moodle 2.3.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.6&lt;br /&gt;
| 18 March 2013&lt;br /&gt;
| 2012062506&lt;br /&gt;
| [[Moodle 2.3.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.7&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2012062507&lt;br /&gt;
| [[Moodle 2.3.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.8&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2012062508&lt;br /&gt;
| [[Moodle 2.3.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.9&lt;br /&gt;
| 9 September 2013&lt;br /&gt;
| 2012062509&lt;br /&gt;
| [[Moodle 2.3.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.10&lt;br /&gt;
| 11 November 2013&lt;br /&gt;
| 2012062510&lt;br /&gt;
| [[Moodle 2.3.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.11&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2012062511&lt;br /&gt;
| [[Moodle 2.3.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.3.x ended June 2013 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.3.x ended December 2013 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.2==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2&lt;br /&gt;
| 5 December 2011&lt;br /&gt;
| 2011120500&lt;br /&gt;
| [[Moodle 2.2 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/22/en/Upgrading_to_Moodle_2.2 Upgrading to 2.2]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.1&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2011120501&lt;br /&gt;
| [[Moodle 2.2.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.2&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2011120502&lt;br /&gt;
| [[Moodle 2.2.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.3&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2011120503&lt;br /&gt;
| [[Moodle 2.2.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.4&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2011120504&lt;br /&gt;
| [[Moodle 2.2.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.5&lt;br /&gt;
| 10 September 2012&lt;br /&gt;
| 2011120505&lt;br /&gt;
| [[Moodle 2.2.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.6&lt;br /&gt;
| 12 November 2012&lt;br /&gt;
| 2011120506&lt;br /&gt;
| [[Moodle 2.2.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.7&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 2011120507&lt;br /&gt;
| [[Moodle 2.2.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.8&lt;br /&gt;
| 11 March 2013&lt;br /&gt;
| 2011120508&lt;br /&gt;
| [[Moodle 2.2.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.9&lt;br /&gt;
| 18 March 2013&lt;br /&gt;
| 2011120509&lt;br /&gt;
| [[Moodle 2.2.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.10&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2011120510&lt;br /&gt;
| [[Moodle 2.2.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.11&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2011120511&lt;br /&gt;
| [[Moodle 2.2.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.2.x ended December 2012 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.2.x ended June 2013 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.1==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1&lt;br /&gt;
| 1 July 2011&lt;br /&gt;
| 2011070100&lt;br /&gt;
| [[Moodle 2.1 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/21/en/Upgrading_to_Moodle_2.1 Upgrading to 2.1]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.1&lt;br /&gt;
| 1 August 2011&lt;br /&gt;
| 2011070101&lt;br /&gt;
| [[Moodle 2.1.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.2&lt;br /&gt;
| 10 October 2011&lt;br /&gt;
| 2011070102&lt;br /&gt;
| [[Moodle 2.1.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.3&lt;br /&gt;
| 28 November 2011&lt;br /&gt;
| 2011070103&lt;br /&gt;
| [[Moodle 2.1.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.4&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2011070104&lt;br /&gt;
| [[Moodle 2.1.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.5&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2011070105&lt;br /&gt;
| [[Moodle 2.1.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.6&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2011070106&lt;br /&gt;
| [[Moodle 2.1.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.7&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2011070107&lt;br /&gt;
| [[Moodle 2.1.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.8&lt;br /&gt;
| 10 September 2012&lt;br /&gt;
| 2011070108&lt;br /&gt;
| [[Moodle 2.1.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.9&lt;br /&gt;
| 12 November 2012&lt;br /&gt;
| 2011070109&lt;br /&gt;
| [[Moodle 2.1.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.10&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 2011070110&lt;br /&gt;
| [[Moodle 2.1.10 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.1.x ended June 2012 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.1.x ended December 2012 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.0==&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0&lt;br /&gt;
| 24 November 2010&lt;br /&gt;
| 2010112400&lt;br /&gt;
| [[Moodle 2.0 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/20/en/Upgrading_to_Moodle_2.0 Upgrading to 2.0]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.1&lt;br /&gt;
| 25 December 2010&lt;br /&gt;
| 2010122500&lt;br /&gt;
| [[Moodle 2.0.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.2&lt;br /&gt;
| 21 February 2011&lt;br /&gt;
| 2011022100&lt;br /&gt;
| [[Moodle 2.0.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.3&lt;br /&gt;
| 5 May 2011&lt;br /&gt;
| 2011033003&lt;br /&gt;
| [[Moodle 2.0.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.4&lt;br /&gt;
| 1 August 2011&lt;br /&gt;
| 2011033004&lt;br /&gt;
| [[Moodle 2.0.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.5&lt;br /&gt;
| 10 October 2011&lt;br /&gt;
| 2011033005&lt;br /&gt;
| [[Moodle 2.0.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.6&lt;br /&gt;
| 28 November 2011&lt;br /&gt;
| 2011033006&lt;br /&gt;
| [[Moodle 2.0.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.7&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2011033007&lt;br /&gt;
| [[Moodle 2.0.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.8&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2011033008&lt;br /&gt;
| [[Moodle 2.0.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.9&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2011033009&lt;br /&gt;
| [[Moodle 2.0.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.10&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2011033010&lt;br /&gt;
| [[Moodle 2.0.10 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.0.x ended December 2011 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.0.x ended June 2012 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.9==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9&lt;br /&gt;
| 3 March 2008&lt;br /&gt;
| 2007101509 &lt;br /&gt;
| [[Moodle 1.9 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/19/en/Upgrading_to_Moodle_1.9 Upgrading to 1.9]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.1&lt;br /&gt;
| 15 May 2008&lt;br /&gt;
| 2007101512 &lt;br /&gt;
| [[Moodle 1.9.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.2&lt;br /&gt;
| 11 July 2008&lt;br /&gt;
| 2007101520&lt;br /&gt;
| [[Moodle 1.9.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.3&lt;br /&gt;
| 15 October 2008&lt;br /&gt;
| 2007101530&lt;br /&gt;
| [[Moodle 1.9.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.4&lt;br /&gt;
| 28 January 2009&lt;br /&gt;
| 2007101540&lt;br /&gt;
| [[Moodle 1.9.4 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.5&lt;br /&gt;
| 13 May 2009&lt;br /&gt;
| 2007101550&lt;br /&gt;
| [[Moodle 1.9.5 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.6&lt;br /&gt;
| 21 October 2009&lt;br /&gt;
| 2007101560&lt;br /&gt;
| [[Moodle 1.9.6 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.7&lt;br /&gt;
| 25 November 2009&lt;br /&gt;
| 2007101570&lt;br /&gt;
| [[Moodle 1.9.7 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.8&lt;br /&gt;
| 25 March 2010&lt;br /&gt;
| 2007101580.00&lt;br /&gt;
| [[Moodle 1.9.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.9&lt;br /&gt;
| 8 June 2010&lt;br /&gt;
| 2007101590.00&lt;br /&gt;
| [[Moodle 1.9.9 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.10&lt;br /&gt;
| 25 October 2010&lt;br /&gt;
| 2007101591.00&lt;br /&gt;
| [[Moodle 1.9.10 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.11&lt;br /&gt;
| 21 February 2011&lt;br /&gt;
| 2007101591.02&lt;br /&gt;
| [[Moodle 1.9.11 release notes|Release Notes]] &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.12&lt;br /&gt;
| 10 May 2011&lt;br /&gt;
| 2007101591.03&lt;br /&gt;
| [[Moodle 1.9.12 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.13&lt;br /&gt;
| 1 August 2011&lt;br /&gt;
| 2007101591.04&lt;br /&gt;
| [[Moodle 1.9.13 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.14&lt;br /&gt;
| 10 October 2011&lt;br /&gt;
| 2007101591.06&lt;br /&gt;
| [[Moodle 1.9.14 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.15&lt;br /&gt;
| 28 November 2011&lt;br /&gt;
| 2007101591.07&lt;br /&gt;
| [[Moodle 1.9.15 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.16&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2007101591.10&lt;br /&gt;
| [[Moodle 1.9.16 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.17&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2007101591.12&lt;br /&gt;
| [[Moodle 1.9.17 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.18&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2007101591.16&lt;br /&gt;
| [[Moodle 1.9.18 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.19&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2007101592.00&lt;br /&gt;
| [[Moodle 1.9.19 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 1.9.x has ended June 2011 (3.5 years).&lt;br /&gt;
 Bug fixes for security issues in 1.9.x by Moodle HQ ended June 2012 (4.5 years).&lt;br /&gt;
 Bug fixes for security issues in 1.9.19+ branch by [http://catalyst.net.nz Catalyst IT] ended [http://moodle.org/mod/forum/discuss.php?d=199706 Dec 2013] (6 years).&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.8==&lt;br /&gt;
*[[Moodle 1.8 release notes|Moodle 1.8]] - 30 March 2007&lt;br /&gt;
*[[Moodle 1.8.1 release notes|Moodle 1.8.1]] - 14 June 2007&lt;br /&gt;
*[[Moodle 1.8.2 release notes|Moodle 1.8.2]] - 8 July 2007&lt;br /&gt;
*[[Moodle 1.8.3 release notes|Moodle 1.8.3]] - 11 October 2007&lt;br /&gt;
*[[Moodle 1.8.4 release notes|Moodle 1.8.4]] - 11 January 2008&lt;br /&gt;
*[[Moodle 1.8.5 release notes|Moodle 1.8.5]] - 8 April 2008&lt;br /&gt;
*[[Moodle 1.8.6 release notes|Moodle 1.8.6]] - 11 July 2008&lt;br /&gt;
*[[Moodle 1.8.7 release notes|Moodle 1.8.7]] - 15 October 2008&lt;br /&gt;
*[[Moodle 1.8.8 release notes|Moodle 1.8.8]] - 28 January 2009&lt;br /&gt;
*[[Moodle 1.8.9 release notes|Moodle 1.8.9]] - 15 May 2009&lt;br /&gt;
*[[Moodle 1.8.10 release notes|Moodle 1.8.10]] - 26 October 2009&lt;br /&gt;
*[[Moodle 1.8.11 release notes|Moodle 1.8.11]] - 25 November 2009&lt;br /&gt;
*[[Moodle 1.8.12 release notes|Moodle 1.8.12]] - 27 March 2010&lt;br /&gt;
*[[Moodle 1.8.13 release notes|Moodle 1.8.13]] - 8 June 2010&lt;br /&gt;
*[[Moodle 1.8.14 release notes|Moodle 1.8.14]] - 3 December 2010&lt;br /&gt;
*Support has ended &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.7==&lt;br /&gt;
*[[Moodle 1.7 release notes|Moodle 1.7]] - 7 November 2006&lt;br /&gt;
*[[Moodle 1.7.1 release notes|Moodle 1.7.1]] - 17 January 2007&lt;br /&gt;
*[[Moodle 1.7.2 release notes|Moodle 1.7.2]] - 30 March 2007&lt;br /&gt;
*[[Moodle 1.7.3 release notes|Moodle 1.7.3]] - 11 October 2007&lt;br /&gt;
*[[Moodle 1.7.4 release notes|Moodle 1.7.4]] - 11 January 2008&lt;br /&gt;
*[[Moodle 1.7.5 release notes|Moodle 1.7.5]] - 11 July 2008&lt;br /&gt;
*[[Moodle 1.7.6 release notes|Moodle 1.7.6]] - 15 October 2008&lt;br /&gt;
*[[Moodle 1.7.7 release notes|Moodle 1.7.7]] - 28 January 2009&lt;br /&gt;
*Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.6==&lt;br /&gt;
*[[Moodle 1.6 release notes|Moodle 1.6]] - 20 June 2006&lt;br /&gt;
*[[Moodle 1.6.1 release notes|Moodle 1.6.1]] - 20 July 2006&lt;br /&gt;
*[[Moodle 1.6.2 release notes|Moodle 1.6.2]] - 12 September 2006&lt;br /&gt;
*[[Moodle 1.6.3 release notes|Moodle 1.6.3]] - 10 October 2006&lt;br /&gt;
*[[Moodle 1.6.4 release notes|Moodle 1.6.4]] - 17 January 2007&lt;br /&gt;
*[[Moodle 1.6.5 release notes|Moodle 1.6.5]] - 30 March 2007&lt;br /&gt;
*Moodle 1.6.6 - 11 January 2008&lt;br /&gt;
*Moodle 1.6.7 - 11 July 2008&lt;br /&gt;
*[[Moodle 1.6.8 release notes|Moodle 1.6.8]] - 15 October 2008&lt;br /&gt;
*[[Moodle 1.6.9 release notes|Moodle 1.6.9]] - 28 January 2009&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.5==&lt;br /&gt;
*[[Moodle 1.5 release notes|Moodle 1.5]] - 5 June 2005&lt;br /&gt;
*[[Moodle 1.5.1 release notes|Moodle 1.5.1]] - 8 July 2005&lt;br /&gt;
*[[Moodle 1.5.2 release notes|Moodle 1.5.2]] - 16 July 2005&lt;br /&gt;
*[[Moodle 1.5.3 release notes|Moodle 1.5.3]] - 11 November 2005&lt;br /&gt;
*[[Moodle 1.5.4 release notes|Moodle 1.5.4]] - 21 May 2006&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.4==&lt;br /&gt;
*Moodle 1.4 - 31 August 2004&lt;br /&gt;
*Moodle 1.4.1 - 12 September 2004&lt;br /&gt;
*Moodle 1.4.2 - 5 November 2004&lt;br /&gt;
*Moodle 1.4.3 - 21 December 2004&lt;br /&gt;
*Moodle 1.4.4 - 7 March 2005 &lt;br /&gt;
*[[Moodle 1.4.5 release notes|Moodle 1.4.5]] - 7 May 2005&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.3==&lt;br /&gt;
*Moodle 1.3 - 25 May 2004&lt;br /&gt;
*Moodle 1.3.1 - 4 June 2004&lt;br /&gt;
*Moodle 1.3.2 - 9 July 2004&lt;br /&gt;
*Moodle 1.3.3 - 16 July 2004&lt;br /&gt;
*Moodle 1.3.4 - 11 August 2004&lt;br /&gt;
*Moodle 1.3.5 - 9 September 2004&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.2==&lt;br /&gt;
*Moodle 1.2 - 20 March 2004&lt;br /&gt;
*Moodle 1.2.1 - 25 March 2004&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.1==&lt;br /&gt;
*Moodle 1.1 - 29 August 2003&lt;br /&gt;
*Moodle 1.1.1 - 11 September 2003&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.0==&lt;br /&gt;
*Moodle 1.0 - 20 August 2002&lt;br /&gt;
*Moodle 1.0.1 - 26 August 2002&lt;br /&gt;
*Moodle 1.0.2 - 2 September 2002&lt;br /&gt;
*Moodle 1.0.3 - 5 September 2002&lt;br /&gt;
*Moodle 1.0.4 - 10 September 2002&lt;br /&gt;
*Moodle 1.0.5 - 27 September 2002&lt;br /&gt;
*Moodle 1.0.6 - 26 October 2002&lt;br /&gt;
:: 1.0.6.1 - 6 November 2002&lt;br /&gt;
:: 1.0.6.2 - 11 November 2002&lt;br /&gt;
:: 1.0.6.3 - 14 November 2002&lt;br /&gt;
:: 1.0.6.4 - 25 November 2002&lt;br /&gt;
*Moodle 1.0.7 - 9 December 2002&lt;br /&gt;
*Moodle 1.0.8 - 7 January 2003&lt;br /&gt;
*Moodle 1.0.9 - 30 May 2003&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Roadmap]] - future versions&lt;br /&gt;
*[[Moodle versions]] - an explanation of how our versions work plus version numbers for each release (for $plugin-&amp;gt;requires)&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Core development]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Historique des versions]]&lt;br /&gt;
[[es:dev/Historia de las versiones]]&lt;br /&gt;
[[de:Versionshistorie]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.6&amp;diff=57812</id>
		<title>Category:Moodle 3.6</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.6&amp;diff=57812"/>
		<updated>2020-08-28T12:52:23Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages that relate to the planning and development of Moodle 3.6 features.&lt;br /&gt;
&lt;br /&gt;
[[fr:Catégorie:Moodle 3.6]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.7&amp;diff=57811</id>
		<title>Category:Moodle 3.7</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.7&amp;diff=57811"/>
		<updated>2020-08-28T12:52:04Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages that relate to the planning and development of Moodle 3.7 features.&lt;br /&gt;
&lt;br /&gt;
[[fr:Catégorie:Moodle 3.7]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.8&amp;diff=57810</id>
		<title>Category:Moodle 3.8</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.8&amp;diff=57810"/>
		<updated>2020-08-28T12:51:45Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages that relate to the planning and development of Moodle 3.8 features.&lt;br /&gt;
&lt;br /&gt;
[[fr:Catégorie:Moodle 3.8]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.9&amp;diff=57809</id>
		<title>Category:Moodle 3.9</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.9&amp;diff=57809"/>
		<updated>2020-08-28T12:51:23Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages that relate to the planning and development of Moodle 3.9 features.&lt;br /&gt;
&lt;br /&gt;
[[fr:Catégorie:Moodle 3.9]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.10&amp;diff=57808</id>
		<title>Category:Moodle 3.10</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.10&amp;diff=57808"/>
		<updated>2020-08-28T12:50:27Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages that relate to the planning and development of Moodle 3.10 features.&lt;br /&gt;
&lt;br /&gt;
[[fr:Catégorie:Moodle 3.10]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=New_docs_version_process&amp;diff=57624</id>
		<title>New docs version process</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=New_docs_version_process&amp;diff=57624"/>
		<updated>2020-06-17T14:17:49Z</updated>

		<summary type="html">&lt;p&gt;Fox: Check (and update if needed) Upgrading and Upgrade overview pages&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page describes the procedures for creating a new Moodle Docs version wiki.&lt;br /&gt;
&lt;br /&gt;
==4 weeks prior==&lt;br /&gt;
&lt;br /&gt;
Tidying up in current latest version wiki:&lt;br /&gt;
&lt;br /&gt;
# Delete https://docs.moodle.org/en/Special:BrokenRedirects&lt;br /&gt;
# Edit https://docs.moodle.org/en/Special:DoubleRedirects (ignoring redirects to dev docs)&lt;br /&gt;
# Check and delete as necessary https://docs.moodle.org/en/Special:NewFiles&lt;br /&gt;
# Check and delete as necessary https://docs.moodle.org/en/Special:ListDuplicatedFiles&lt;br /&gt;
# Check and delete as necessary https://docs.moodle.org/en/Special:UnusedFiles&lt;br /&gt;
# (Check and delete as necessary https://docs.moodle.org/en/Special:ShortPages )&lt;br /&gt;
&lt;br /&gt;
Create a tracker issue for creating new en and de version wikis similar to MDLSITE-5946.&lt;br /&gt;
&lt;br /&gt;
==3 weeks prior==&lt;br /&gt;
&lt;br /&gt;
In new version wiki:&lt;br /&gt;
&lt;br /&gt;
# Edit MediaWiki:MoodleDocsVersionLinks &lt;br /&gt;
# Edit Main_page&lt;br /&gt;
# Add message to MediaWiki:Sitenotice&lt;br /&gt;
# Remove new features template from all pages in Category:New_features&lt;br /&gt;
# Edit Template:New_features and Category:New_features&lt;br /&gt;
# Go through [https://tracker.moodle.org/issues/?jql=labels%20%3D%20docs_required tracker issues with the docs_required label] and the release notes for the upcoming release and add documentation on new features plus the new features template&lt;br /&gt;
# Create Upgrading_to_Moodle_3.x and redirect to Upgrading&lt;br /&gt;
# Update version number in Template:Version and Template:Version2 and Git for Administrators&lt;br /&gt;
# Review Special:WantedPages&lt;br /&gt;
# Review Special:LonelyPages&lt;br /&gt;
# Review instances of &amp;quot;(new in 3.x)&amp;quot; text (not always necessary to remove them)&lt;br /&gt;
# Add link to new version wiki to https://docs.moodle.org/dev/MediaWiki:Sidebar&lt;br /&gt;
# Add link to new version wiki to https://docs.moodle.org/en/MoodleDocs:Overview&lt;br /&gt;
# Post on moodle.org in the Moodle community sites forum about the new version wikis e.g. [https://moodle.org/mod/forum/discuss.php?d=404029 Moodle Docs 3.9 wikis now available]&lt;br /&gt;
&lt;br /&gt;
==1 week prior==&lt;br /&gt;
&lt;br /&gt;
Create a tracker issue for making the new wiki default, similar to MDLSITE-6027.&lt;br /&gt;
&lt;br /&gt;
In new wiki:&lt;br /&gt;
&lt;br /&gt;
* Remove message in MediaWiki:Sitenotice&lt;br /&gt;
* Check (and update if needed) Upgrading and Upgrade overview pages&lt;br /&gt;
&lt;br /&gt;
In all older version wikis:&lt;br /&gt;
&lt;br /&gt;
* Edit https://docs.moodle.org/en/MediaWiki:MoodleDocsVersionLinks to add the new version and remove older versions (though keeping 3.5 as [[Releases|LTS release]])&lt;br /&gt;
&lt;br /&gt;
==Day of release==&lt;br /&gt;
&lt;br /&gt;
In previous latest version wiki:&lt;br /&gt;
&lt;br /&gt;
* Edit https://docs.moodle.org/en/MediaWiki:Noarticletext to make it like https://docs.moodle.org/2x-1/en/MediaWiki:Noarticletext&lt;br /&gt;
* Edit https://docs.moodle.org/en/Creating_SCORM_Content to make it like https://docs.moodle.org/2x-1/en/Creating_SCORM_Content &lt;br /&gt;
* Go through Special:RecentChanges in the previous most recent version wiki and add relevant changes to the new version wiki&lt;br /&gt;
* Edit https://docs.moodle.org/en/Awards and add &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#redirect [[:en:Awards]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; so it redirects to the latest version of the page&lt;br /&gt;
* Edit https://docs.moodle.org/en/MoodleDocs:Overview and add &amp;lt;code&amp;gt;&amp;lt;nowiki&amp;gt;#redirect [[:en:MoodleDocs:Overview]]&amp;lt;/nowiki&amp;gt;&amp;lt;/code&amp;gt; so it redirects to the latest version of the page&lt;br /&gt;
* Create MediaWiki:Sitenotice by copying content from https://docs.moodle.org/26/en/MediaWiki:Sitenotice&lt;br /&gt;
&lt;br /&gt;
On moodle.org, dev.moodle.org, download.moodle.org and lang.moodle.org in footersitesmap change the version number.&lt;br /&gt;
&lt;br /&gt;
==Final checks==&lt;br /&gt;
&lt;br /&gt;
* Email notification of watched pages enabled&lt;br /&gt;
* Links without version number e.g. https://docs.moodle.org/en/Main_page redirect to the new version wiki&lt;br /&gt;
* New version wiki listed in https://docs.moodle.org/overview/ &lt;br /&gt;
&lt;br /&gt;
[[Category:Documentation]]&lt;br /&gt;
[[Category:Processes]]&lt;br /&gt;
[[Category:Moodle Docs]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.9_release_notes&amp;diff=57469</id>
		<title>Moodle 3.9 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.9_release_notes&amp;diff=57469"/>
		<updated>2020-05-13T14:53:32Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* Server requirements */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released - scheduled for Monday 8 June 2020&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.9%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.9].&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from a previous version, please see [[:en:Upgrading|Upgrading]] in the user docs.&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Requirements still to be reviewed and updated as necessary!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.5 or later&lt;br /&gt;
* PHP version: minimum PHP 7.2.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.8&#039;&#039;. PHP 7.3.x and 7.4.x are supported too. See [[Moodle and PHP]] for details.&lt;br /&gt;
* PHP extension &#039;&#039;&#039;mbstring&#039;&#039;&#039; is required (it was recommended) &lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: Requirements still to be reviewed and updated as necessary!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.5&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.6&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 10.2.29&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2012&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 11.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://whatbrowser.org&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle 3.9:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other highlights==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.8 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.9]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.9]]&lt;br /&gt;
[[es:Notas de Moodle 3.9]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_and_PHP&amp;diff=57461</id>
		<title>Moodle and PHP</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_and_PHP&amp;diff=57461"/>
		<updated>2020-05-11T17:20:04Z</updated>

		<summary type="html">&lt;p&gt;Fox: French link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;PHP7 was released on 3 December 2015 and has significant performance improvement comparing to PHP5. Everybody wants to benefit from it, however the language standards have changed and code written for PHP5 might not work in PHP7. Moodle core and plugins should modify the code so it works the same way on both versions of PHP.&lt;br /&gt;
&lt;br /&gt;
This page contains description of what has been changed in Moodle to make it work on PHP7 and recommendations to plugin developers. Please see also epic issues that combine all the changes that were made in Moodle to ensure PHP compatibility. &#039;&#039;(Note: you must be logged in to tracker to see issues in Epics)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MDL-50565 - &#039;&#039;&#039;PHP 7.0 can be used with Moodle 3.0.1, Moodle 3.1 and later releases.&#039;&#039;&#039; It is also the &#039;&#039;&#039;minimum&#039;&#039;&#039; supported version for Moodle 3.4. See [[Moodle and PHP 7.0 details]] for details.&lt;br /&gt;
&lt;br /&gt;
MDL-55120 - &#039;&#039;&#039;PHP 7.1 can be used with Moodle 3.2 and later releases.&#039;&#039;&#039; It is also the &#039;&#039;&#039;minimum&#039;&#039;&#039; supported version for Moodle 3.7.&lt;br /&gt;
&lt;br /&gt;
MDL-60279 - &#039;&#039;&#039;PHP 7.2 can be used with Moodle 3.4 and later releases.&#039;&#039;&#039; It is also the &#039;&#039;&#039;minimum&#039;&#039;&#039; supported version for Moodle 3.9.&lt;br /&gt;
&lt;br /&gt;
MDL-63420 - &#039;&#039;&#039;PHP 7.3 can be used with Moodle 3.6.4, Moodle 3.7 and later releases.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MDL-66260 - &#039;&#039;&#039;PHP 7.4 can be used with Moodle 3.8.3, Moodle 3.9 and later releases.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[fr:Moodle et PHP]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=QA_testing&amp;diff=56725</id>
		<title>QA testing</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=QA_testing&amp;diff=56725"/>
		<updated>2019-12-06T09:55:27Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Quality Assurance&#039;&#039;&#039; tests look at the functionality of Moodle from a user&#039;s point of view.  &lt;br /&gt;
&lt;br /&gt;
Real users systematically try each feature in Moodle and test that it works in the current version of the Moodle code. These tests are repeated in series of cycles, usually 4 weeks before a major release, once all major features have landed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;QA testing latest&#039;&#039;&#039;: &#039;&#039;A 100% pass rate was obtained in Moodle 3.8 QA testing. Many thanks to all our [[Testing credits|QA testers]].&#039;&#039;&amp;lt;/p&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Getting involved==&lt;br /&gt;
&lt;br /&gt;
Would you like to help with QA testing?  If so, please make sure you have created an account in the [[Tracker_introduction|Moodle tracker]], then contact [https://moodle.org/user/profile.php?id=24152&amp;amp;course=1 Helen]. Also, make sure you&#039;re subscribed to the [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum] in order to receive QA testing news updates.&lt;br /&gt;
&lt;br /&gt;
All testers are members of the testers group in the Moodle Tracker, enabling them to pass or fail QA tests and add comments.&lt;br /&gt;
&lt;br /&gt;
==Running tests==&lt;br /&gt;
&lt;br /&gt;
# Go to the QA testing dashboard  and choose a test from the list of current QA cycle open issues. When viewing a test, if you wish, you can click the &#039;Assign to me&#039; link on the right, so that nobody else chooses the same test to run. (If you then find you are unable to run the test, you can click the Assign button and set the assignee as &#039;Unassigned&#039;.) Please note:&lt;br /&gt;
#* Only assign an issue to yourself which no one else is testing (Assignee = Unassigned).&lt;br /&gt;
#* Only assign one issue at a time unless you plan to test a number of related issues within the next 24 hours. In other words, don&#039;t assign several issues to yourself then do nothing for several days. ;-)&lt;br /&gt;
#* The label &#039;&#039;test_server_required&#039;&#039; indicates issues that can&#039;t be tested on the QA testing site. The label &#039;&#039;credentials_required&#039;&#039; indicates that credentials such as an OAuth 2 service client ID and secret are required.&lt;br /&gt;
# Using either the [https://qa.moodledemo.net/ Moodle QA Testing Site] or your own test site running the latest Moodle 3.x dev (available from Git on the integration/master branch &#039;&#039;&amp;lt;nowiki&amp;gt;git://git.moodle.org/integration.git&amp;lt;/nowiki&amp;gt;&#039;&#039;) with [[:en:Debugging|debugging]] set to developer, perform each of the steps listed in the test. &#039;&#039;If it makes sense, please test using the currently supported themes, Boost and Classic.&#039;&#039;&lt;br /&gt;
# Choose an appropriate workflow action:&lt;br /&gt;
#* &#039;&#039;Pass&#039;&#039; - Test runs perfectly. Add comment such as feedback about a new feature, browsers used for testing (if applicable), or simply &amp;quot;This test passes - yippee!&amp;quot;&lt;br /&gt;
#* &#039;&#039;Fail&#039;&#039; - Something doesn&#039;t work, or you obtain debugging messages. Add comment describing the step that doesn&#039;t work. If in doubt whether to pass a test, give it a fail and add a comment describing your doubts.&lt;br /&gt;
#* &#039;&#039;Obsolete&#039;&#039; - Test is no longer relevant in the current Moodle version. Add comment explaining why.&lt;br /&gt;
&lt;br /&gt;
If you notice that the test description is out-of-date, add a comment mentioning that it needs updating. Alternatively, if you&#039;d like to help with updating the test yourself, see below.&lt;br /&gt;
&lt;br /&gt;
===Moodle QA Testing Site===&lt;br /&gt;
&lt;br /&gt;
The [https://qa.moodledemo.net/ Moodle QA Testing Site] is updated daily at around 13:00 UTC with the latest bug fixes to enable you to re-run QA tests.&lt;br /&gt;
&lt;br /&gt;
To prevent the site being used for sending spam, no emails are sent from it. Thus, tests involving email cannot be run using the Moodle QA Testing Site. (If such tests are attempted, an email debug message is displayed. This is not a bug but rather expected behaviour.)&lt;br /&gt;
&lt;br /&gt;
Teacher and student accounts are provided. Please contact [https://moodle.org/user/profile.php?id=24152&amp;amp;course=1 Helen] if you would like admin or manager access to the Moodle QA Testing Site for running certain tests.&lt;br /&gt;
&lt;br /&gt;
==&amp;lt;div id=&amp;quot;failedTests&amp;quot;&amp;gt;Failed tests&amp;lt;/div&amp;gt;==&lt;br /&gt;
&lt;br /&gt;
So you ran a test and it failed? Congratulations on finding a bug! Please do the following.&lt;br /&gt;
&lt;br /&gt;
# Click the Fail button at the top of the page.&lt;br /&gt;
# Add a comment to the QA test stating that there was a problem and that you will report it as a Moodle bug.&lt;br /&gt;
# Note the MDLQA number; it will be something like &amp;lt;nowiki&amp;gt;MDLQA-448&amp;lt;/nowiki&amp;gt;.&lt;br /&gt;
# Try searching for whether the bug has been reported previously, and if not create a new issue for it (as described in [[Tracker introduction]]).&lt;br /&gt;
# In the new Moodle (MDL) issue select &#039;Link&#039; from the &#039;More actions&#039; dropdown menu. &amp;lt;br /&amp;gt;[[Image:LinkIssue.png|150px|Linking to the QA issue in the tracker]]&lt;br /&gt;
# Link to the QA test by selecting &#039;blocks&#039; as the link type, entering the MDLQA number that you noted earlier, and optionally adding a comment. &amp;lt;br /&amp;gt;[[Image:LinkDetails.png|150px|Adding details for a link to the QA issue]]&lt;br /&gt;
# Give the issue the label &#039;mdlqa&#039;. &lt;br /&gt;
# (Optional) Add yourself as a watcher to the MDL issue so that you receive email notification when the issue is fixed.&lt;br /&gt;
# When the MDL issue is fixed, hopefully within a day or two, the QA test can be reset and can then be run again.&lt;br /&gt;
&lt;br /&gt;
==Resetting tests==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note for integrators:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
After integrating a fix, &lt;br /&gt;
&lt;br /&gt;
# Reset the MDLQA test, adding a comment.&lt;br /&gt;
# Remove the &#039;mdlqa&#039; label from the MDL issue.&lt;br /&gt;
# If the issue doesn&#039;t have testing instructions, pass it with message &amp;quot;Will be tested by MDLQA-XXXX&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The tester will then receive email notification that the bug is fixed and will hopefully decide to run the test again soon.&lt;br /&gt;
&lt;br /&gt;
==New QA tests required==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note for developers:&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If an issue fix cannot be covered by automated tests, &lt;br /&gt;
&lt;br /&gt;
# Add the label &#039;qa_test_required&#039; to the issue.&lt;br /&gt;
# Add a comment explaining why it can&#039;t be covered by automated tests and suggesting which steps of the testing instructions should be included in a QA test e.g. steps 6-10 or all steps.&lt;br /&gt;
&lt;br /&gt;
QA tests will then be written and included in the next QA cycle. For issues with long testing instructions, several QA tests will be written to cover the issue. If appropriate, activities etc. will be set up on the [https://qa.moodledemo.net/ Moodle QA Testing Site] to enable the issue to be easily tested in future. &lt;br /&gt;
&lt;br /&gt;
Similarly, for new features and improvements which would benefit from exploratory testing,&lt;br /&gt;
&lt;br /&gt;
# Add the label &#039;qa_test_required&#039; to the issue.&lt;br /&gt;
# Add a comment mentioning that exploratory testing is required.&lt;br /&gt;
&lt;br /&gt;
Exploratory QA tests will then be written and included in the next QA cycle and then removed.&lt;br /&gt;
&lt;br /&gt;
==Updating tests==&lt;br /&gt;
&lt;br /&gt;
QA tests often become out-of-date due to new developments. If you would like to help with updating tests, you&#039;ll need to be a member of the test writers group in the Tracker. Please contact Helen about being added.&lt;br /&gt;
&lt;br /&gt;
To update a QA test:&lt;br /&gt;
&lt;br /&gt;
# Search for the master copy of the test - with affects version as &#039;Master copy&#039; and MDLQA-1 as parent.&lt;br /&gt;
# Edit the test description.&lt;br /&gt;
# Optional: Add a comment describing your edit.&lt;br /&gt;
&lt;br /&gt;
==Writing new tests==&lt;br /&gt;
&lt;br /&gt;
Would you like to help with writing new QA tests? If so, as for updating tests, you&#039;ll need to be a member of the test writers group in the Tracker. Please contact Helen about being added.&lt;br /&gt;
&lt;br /&gt;
To create a new QA test:&lt;br /&gt;
&lt;br /&gt;
# Choose an issue from the  [https://tracker.moodle.org/issues/?jql=labels%20%3D%20qa_test_required%20AND%20status%20%3D%20Closed closed qa_test_required-labelled issues] &lt;br /&gt;
# Do a quick search of MDLQA-1 to check if there is an existing test which can be updated&lt;br /&gt;
# If not, create a sub-task of MDLQA-1&lt;br /&gt;
# Select Master copy as affected version&lt;br /&gt;
# Select appropriate components including at least one of the following: User, Student, Teacher, Administrator&lt;br /&gt;
# Set assignee as unassigned&lt;br /&gt;
# Write the test (usually between 3 and 10 steps). It&#039;s a good idea to try doing the steps yourself as you write the test.&lt;br /&gt;
# For tests which can’t be run on the QA site, label test_server_required. For OAuth 2 tests and any other tests which require a client ID or secret to be entered, label credentials_required.&lt;br /&gt;
# For issues which specifically mention in the testing instructions to test in different browsers, use the phrase “Test in as many browsers as possible and mention in a comment which ones you’ve used.”&lt;br /&gt;
# Go to the MDL issue and create a ‘has a QA test’ link to the new QA test, adding a comment “Thanks for this improvement which is now covered by the QA test MDLQA....”, and remove the qa_test_required label. &#039;&#039;Make sure that all QA tests are linked back to a corresponding MDL issue.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
New tests will be included in the next QA cycle.&lt;br /&gt;
&lt;br /&gt;
==Feedback==&lt;br /&gt;
&lt;br /&gt;
Feedback on all aspects of our QA testing process is welcome. If you have any questions or comments, please post in the [https://moodle.org/mod/forum/view.php?id=56 Testing and QA forum].&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [https://tracker.moodle.org/secure/Dashboard.jspa?selectPageId=11454 QA testing dashboard]&lt;br /&gt;
* [[Testing credits]]&lt;br /&gt;
* [[MDLQA-features]]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=351302 Useful tips for QA testing]&lt;br /&gt;
&lt;br /&gt;
Comments on tests from previous QA cycles:&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-150 Moodle 2.0 QA Cycle 1]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-328 Moodle 2.0 QA Cycle 2]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-540 Moodle 2.0.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-944 Moodle 2.1 QA Cycle 1]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-1190 Moodle 2.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-1814 Moodle 2.3 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-4602 Moodle 2.4 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-5267 Moodle 2.5 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-5740 Moodle 2.6 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-6693 Moodle 2.7 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-7170 Moodle 2.8 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-7660 Moodle 2.9 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-8205 Moodle 3.0 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-9267 Moodle 3.1 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-9827 Moodle 3.2 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-10403 Moodle 3.3 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-10999 Moodle 3.4 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-11698 Moodle 3.5 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-12282 Moodle 3.6 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-12911 Moodle 3.7 QA]&lt;br /&gt;
* [https://tracker.moodle.org/browse/MDLQA-13517 Moodle 3.8 QA]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_Development_kit&amp;diff=56720</id>
		<title>Moodle Development kit</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_Development_kit&amp;diff=56720"/>
		<updated>2019-12-04T10:22:27Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* Backporting a fix */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Every developer creates simple tools to avoid repeating cumbersome and/or boring tasks, and that is precisely why MDK has been created: to pack all those useful tools in a portable way across systems. Initially developed in Bash, the project moved to Python to avoid dealing with inconsistencies between Unix platforms, and eventually to support Windows.&lt;br /&gt;
&lt;br /&gt;
= Key concept =&lt;br /&gt;
&lt;br /&gt;
The most important concept of MDK is that it works with Moodle instances. An instance of Moodle is a directory in which you have checked out a particular version together with a database using a specific database engine. This means that if you want to work on Moodle 2.3 and 2.4, using both MySQL and PostgreSQL, you will have four separate instance directories. This choice was made because it is the safest, clearest, and most straightforward solution. &lt;br /&gt;
&lt;br /&gt;
= Typical workflows using MDK =&lt;br /&gt;
&lt;br /&gt;
To discover what MDK can do for you, here are a few common tasks it can achieve. More on [https://github.com/FMCorz/mdk/wiki/Typical-workflows MDK&#039;s wiki].&lt;br /&gt;
&lt;br /&gt;
== Installing a new instance ==&lt;br /&gt;
&lt;br /&gt;
Say we need to create a new instance of Moodle 2.4 and install it with PostgreSQL. We also want the instance to be ready for development with appropriate config settings. We also want to create a bunch of user accounts.&lt;br /&gt;
&lt;br /&gt;
 mdk create -i -v 24 -e pgsql -r dev users&lt;br /&gt;
or the equivalent long form:&lt;br /&gt;
 mdk create --install --version 24 --engine pgsql --run dev users&lt;br /&gt;
&lt;br /&gt;
These options include:&lt;br /&gt;
 --install: launch the installation script after creating the instance&lt;br /&gt;
 --engine: database engine to install the instance on (must be used with --install), default: mysqli&lt;br /&gt;
 --version: version of Moodle create an instance of (default: &#039;master&#039;)&lt;br /&gt;
 --run: scripts to run after installation (default: none)&lt;br /&gt;
&lt;br /&gt;
More information about scripts is available here: https://github.com/FMCorz/mdk/tree/master/mdk/scripts&lt;br /&gt;
&lt;br /&gt;
The above command is equivalent to doing:&lt;br /&gt;
&lt;br /&gt;
 mkdir /dir/to/stable_24/moodle&lt;br /&gt;
 mkdir /dir/to/stable_24/moodledata&lt;br /&gt;
 ln -s /dir/to/stable_24/moodle /var/www/stable_24&lt;br /&gt;
 git clone git://git.moodle.org/moodle.git /dir/to/moodle&lt;br /&gt;
 cd /dir/to/stable_24/moodle&lt;br /&gt;
 php admin/cli/install.php --wwwroot=&amp;quot;http://localhost/stable_24&amp;quot; --dataroot=/dir/to/stable_24/moodledata --dbtype=pgsql --dbname=stable24 --dbuser=root --dbpass=root --dbhost=localhost --fullname=&amp;quot;Stable 24 PostgreSQL&amp;quot; --shortname=stable_24 --adminuser=admin --adminpass=test --allow-unstable --agree-license --non-interactive&lt;br /&gt;
 vim config.php&lt;br /&gt;
 # Add the following settings:&lt;br /&gt;
 # - $CFG-&amp;gt;sessioncookiepath: /stable_24/&lt;br /&gt;
 # - $CFG-&amp;gt;debug: DEBUG_DEVELOPER&lt;br /&gt;
 # - $CFG-&amp;gt;debugdisplay: 1&lt;br /&gt;
 # - $CFG-&amp;gt;passwordpolicy: 0&lt;br /&gt;
 # - $CFG-&amp;gt;perfdebug: 15&lt;br /&gt;
 # - $CFG-&amp;gt;debugpageinfo: 1&lt;br /&gt;
 # - $CFG-&amp;gt;allowthemechangeonurl: 1&lt;br /&gt;
 # - $CFG-&amp;gt;cachejs: 0&lt;br /&gt;
 # - $CFG-&amp;gt;yuicomboloading: 0&lt;br /&gt;
 # Include FirePHP Core&lt;br /&gt;
 # Login to Moodle&lt;br /&gt;
 # Create 10 students, 3 teachers and 3 managers&lt;br /&gt;
&lt;br /&gt;
You also can specify the name of the instance using the --name or -n parameter. This is necessary to avoid name conflicts when trying to create same Moodle version with different database engines:&lt;br /&gt;
&lt;br /&gt;
 mdk create -i -v 24 -e mysqli -r dev users -n stable_24-mysql&lt;br /&gt;
&lt;br /&gt;
== Fixing an issue ==&lt;br /&gt;
&lt;br /&gt;
 mdk fix 12345&lt;br /&gt;
 # Committing your patch&lt;br /&gt;
 mdk push -t&lt;br /&gt;
&lt;br /&gt;
This is equivalent to doing:&lt;br /&gt;
&lt;br /&gt;
 git branch --track MDL-12345-24 origin/MOODLE_24_STABLE&lt;br /&gt;
 git checkout MDL-12345-24&lt;br /&gt;
 # Committing your patch&lt;br /&gt;
 git push github MDL-12345-24&lt;br /&gt;
 # Editing the tracker issue to add&lt;br /&gt;
 # - Git repository URL&lt;br /&gt;
 # - Git branch for 2.4&lt;br /&gt;
 # - Git compare URL for 2.4&lt;br /&gt;
&lt;br /&gt;
== Peer reviewing a patch ==&lt;br /&gt;
&lt;br /&gt;
Here we want to pull a patch from a tracker issue into a new testing branch, and then run the PHPUnit tests.&lt;br /&gt;
&lt;br /&gt;
 mdk pull 12345 -t&lt;br /&gt;
 mdk phpunit -r&lt;br /&gt;
&lt;br /&gt;
This is the equivalent to doing:&lt;br /&gt;
&lt;br /&gt;
 cd /dir/to/stable_24/moodle&lt;br /&gt;
 git branch --tracker MDL-12345-24-test MOODLE_24_STABLE&lt;br /&gt;
 git checkout MDL-12345-24-test&lt;br /&gt;
 git pull git://github.org/Someone/moodle.git MDL-12345-24&lt;br /&gt;
 # And now the PHPUnit part&lt;br /&gt;
 mkdir /dir/to/stable_24/moodledata_phpu&lt;br /&gt;
 vim config.php&lt;br /&gt;
 # To add&lt;br /&gt;
 # - $CFG-&amp;gt;phpunit_dataroot = &#039;/dir/to/stable_24/moodledata_phpu&#039;;&lt;br /&gt;
 # - $CFG-&amp;gt;phpunit_prefix = &#039;phpu_&#039;;&lt;br /&gt;
 php admin/tool/phpunit/cli/init.php&lt;br /&gt;
 phpunit&lt;br /&gt;
&lt;br /&gt;
For executing only the testcases in a file you can use:&lt;br /&gt;
&lt;br /&gt;
 mdk phpunit -r -u repository/tests/repository_test.php&lt;br /&gt;
&lt;br /&gt;
== Backporting a fix ==&lt;br /&gt;
&lt;br /&gt;
MDK could handle for you most of the cherry-picking work when you backport a fix. To do so, you need to have installed locally instances called &amp;quot;stable_XX&amp;quot; for each version you want to backport your fix. To do so you can use commands like:&lt;br /&gt;
&lt;br /&gt;
 mdk create -v 38 -i -r dev users makecourse -n stable_38&lt;br /&gt;
 mdk create -v 37 -i -r dev users makecourse -n stable_37&lt;br /&gt;
&lt;br /&gt;
Once you have the stable_XX versions, go to the branch you want to backport and execute:&lt;br /&gt;
&lt;br /&gt;
 mdk backport --versions 37 38 --push --update-tracker&lt;br /&gt;
&lt;br /&gt;
The example params are:&lt;br /&gt;
* -v 37 38 backports the patch to the versions 3.7 and 3.8&lt;br /&gt;
* --push pushes the branch to github&lt;br /&gt;
* --update-tracker updates the tracker issue&lt;br /&gt;
&lt;br /&gt;
After the execution, your stable_XX instances will be on the fix branch, commits are pushed to you github project and backport links will be updated in the tracker.&lt;br /&gt;
&lt;br /&gt;
If for some reason one cherry pick could not finish successfully, mdk will ask you if you want to keep this backport or no. If you choose to keep the partial backport, your stable_XX instance will be in cherry-picking state. In that case you need to solve any conflict and use mdk to push your changes:&lt;br /&gt;
&lt;br /&gt;
 # go to your stable_XX with cherry pick conflict&lt;br /&gt;
 # solve conflicts with git mergetool or any other tool&lt;br /&gt;
 git cherry-pick --continue&lt;br /&gt;
 # once all conflicts are solved, push to your repository and tracker using&lt;br /&gt;
 mdk push -t&lt;br /&gt;
&lt;br /&gt;
== Upgrading the instances ==&lt;br /&gt;
&lt;br /&gt;
Say we need to upgrade our instances, as a new weekly release has just been made available.&lt;br /&gt;
 &lt;br /&gt;
 mdk upgrade -u --all&lt;br /&gt;
&lt;br /&gt;
This is the equivalent to doing:&lt;br /&gt;
&lt;br /&gt;
 # For each instance of Moodle...&lt;br /&gt;
 cd /dir/to/stable_24/moodle&lt;br /&gt;
 git checkout MOODLE_24_STABLE&lt;br /&gt;
 git fetch origin&lt;br /&gt;
 git reset --hard origin/MOODLE_24_STABLE&lt;br /&gt;
 php admin/cli/upgrade.php --non-interactive --allow-unstable&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Executing behat tests ==&lt;br /&gt;
&lt;br /&gt;
In order to get the instance ready for acceptance testing (Behat) and run the test feature(s):&lt;br /&gt;
 &lt;br /&gt;
 mdk behat -r --tags=@core_completion&lt;br /&gt;
&lt;br /&gt;
For running only one feature or specific scenario:&lt;br /&gt;
&lt;br /&gt;
 mdk behat -r -n &amp;quot;Name of the feature/scenario&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Features =&lt;br /&gt;
&lt;br /&gt;
For a complete list of the commands MDK has to offer, read through the [https://github.com/FMCorz/mdk#command-list MDK README file] and the [https://github.com/FMCorz/mdk/wiki MDK wiki]. For more detail about each command, simply run them with the flag &#039;--help&#039;.&lt;br /&gt;
&lt;br /&gt;
= Installation =&lt;br /&gt;
&lt;br /&gt;
Please follow the instructions from the [https://github.com/FMCorz/mdk#installation README file].&lt;br /&gt;
&lt;br /&gt;
Note: When you install MDK, you will be asked for the following information (with default responses indicated in square brackets):&lt;br /&gt;
&lt;br /&gt;
*  What user are you initialising MDK for? [default - your current username]&lt;br /&gt;
*   What is the DocumentRoot of your virtual host? [~/www] &amp;lt;- &#039;&#039;&#039;See note below&#039;&#039;&#039;&lt;br /&gt;
*    Where do you want to store your Moodle instances? [~/moodles] &amp;lt;- This can be in your home directory (the default) because a symlink will be created using DocumentRoot&lt;br /&gt;
*    What is your Github username? (Leave blank if not using Github) &lt;br /&gt;
*    What is your MySQL user? [root]&lt;br /&gt;
*    What is your MySQL password? [root]&lt;br /&gt;
*    What is your PostgreSQL user? [root]&lt;br /&gt;
*    What is your PostgreSQL password? [root]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: By default, MDK will install instances to your home directory. A symlink will be created from your DocumentRoot to the install location. You will need to either change the DocumentRoot of your host to the path to your html root directory, e.g. /var/www/html, or create a file in /etc/httpd/conf.d/moodlehq.conf that configures a virtual host in your home directory.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Also note that you may need to set the path variable to null:&#039;&#039;&#039;&lt;br /&gt;
 mdk config set path &amp;quot;&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Upgrading MDK =&lt;br /&gt;
Every Moodle release, a new version of MDK is also being released in order to prepare for the development of the next Moodle version. To upgrade MDK:&lt;br /&gt;
# Update all of the Moodle instances: &#039;&#039;mdk update --all&#039;&#039;&lt;br /&gt;
# Check out the master branch for all of your master instances, e.g. in your stable_master branch: &#039;&#039;git checkout master&#039;&#039;&lt;br /&gt;
# Upgrade MDK&lt;br /&gt;
## Via pip: &#039;&#039;sudo pip install moodle-sdk --upgrade&#039;&#039;&lt;br /&gt;
## Via Homebrew: &#039;&#039;brew upgrade moodle-sdk&#039;&#039;&lt;br /&gt;
# Run MDK doctor to fix its &#039;&#039;masterBranch&#039;&#039; configuration. &#039;&#039;mdk doctor --fix --masterbranch&#039;&#039;&lt;br /&gt;
# Run MDK doctor to check the master instances. &#039;&#039;mdk doctor --all&#039;&#039;&lt;br /&gt;
#* If you don&#039;t see an error saying something like “stable_master is on branch master instead of MOODLE_XX_STABLE”, then you&#039;re all good. Otherwise, do a hard reset your master instances:&lt;br /&gt;
 mdk update -c&lt;br /&gt;
 cd ~/moodles/[integration/stable]_master&lt;br /&gt;
 git checkout master&lt;br /&gt;
 git fetch `mdk config show upstreamRemote`&lt;br /&gt;
 git reset --hard `mdk config show upstreamRemote`/master&lt;br /&gt;
&lt;br /&gt;
= The MDK Suite =&lt;br /&gt;
&lt;br /&gt;
Some other tools have been developed using the name MDK as they are considered as part of the development kit but are often mistaken with the &#039;&#039;real&#039;&#039; MDK. The &#039;&#039;real&#039;&#039; MDK is the command line tool described above.&lt;br /&gt;
&lt;br /&gt;
== MDK Browser Extension ==&lt;br /&gt;
&lt;br /&gt;
Available for both [https://addons.mozilla.org/en-US/firefox/addon/mdk-browser-extension/ Firefox] and [https://chrome.google.com/webstore/detail/mdk-browser-extension/iadpkkojcdoflinpncpkbonnhdlaicnc Chrome], this is a browser extension that allows quick access to useful user-scripts. The scripts add functionality to Moodle.org, Moodle Tracker and your Moodle instances. You can find more information about it on its [https://github.com/danpoltawski/userscripts-moodle public repository].&lt;br /&gt;
&lt;br /&gt;
== MDK Authentication ==&lt;br /&gt;
&lt;br /&gt;
This is an authentication plugin for Moodle 2.x, which not only creates the user if it does not exist in the database yet, but also enrols it as a student, teacher or manager in all the available courses. More information about this plugin is available on the [https://github.com/FMCorz/moodle-auth_mdk public repository].&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer tools]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Release_notes_template&amp;diff=56598</id>
		<title>Release notes template</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Release_notes_template&amp;diff=56598"/>
		<updated>2019-11-05T11:58:06Z</updated>

		<summary type="html">&lt;p&gt;Fox: Small cleaning&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Copy and paste this wiki code into the new release notes page and replace all the missing bits.&lt;br /&gt;
&amp;lt;code text&amp;gt;&lt;br /&gt;
[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
Release date: Not yet released&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%22X.X.X%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in X.X.X].&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
===Database requirements===&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
===Browser support===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date.&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle X.X:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Other highlights==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==For admins==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==For developers==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Items to be added soon...&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Security issues==&lt;br /&gt;
&lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle X.X.X-1 release notes]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle X.X]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Notes de mise à jour de Moodle X.X.X]]&lt;br /&gt;
[[es:Notas de Moodle X.X.X]]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Tips===&lt;br /&gt;
&lt;br /&gt;
The following git command can be used to find all upgrade.txt files that were modified since the last release, so that links to them can be provided in the release notes - typically in the For developers section.&lt;br /&gt;
&lt;br /&gt;
 $ git log --oneline --pretty=&amp;quot;format:&amp;quot; --name-only v3.5.0..v3.6.0-beta | grep upgrade.txt | sort | uniq | while read path; do echo &amp;quot;* [https://git.in.moodle.com/moodle/moodle/blob/v3.6.0-beta/$path $path]&amp;quot;; done&lt;br /&gt;
&lt;br /&gt;
See e.g. [[Moodle 3.6 release notes#Component APIs upgrades]] for how it was used in the past.&lt;br /&gt;
&lt;br /&gt;
[[:es:Plantilla para las notas de versiones|Plantilla en Español]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Processes|Release process]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.5.7_release_notes&amp;diff=56258</id>
		<title>Moodle 3.5.7 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.5.7_release_notes&amp;diff=56258"/>
		<updated>2019-07-08T08:15:37Z</updated>

		<summary type="html">&lt;p&gt;Fox: Version officially out now&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 8 July 2019&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.5.7%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.5.7].&lt;br /&gt;
 &lt;br /&gt;
===Fixes and improvements===&lt;br /&gt;
 &lt;br /&gt;
* MDL-58315 - Boost theme no longer ignores HTML block custom classes &lt;br /&gt;
* MDL-65581 - Hidden blocks can once again be unhidden&lt;br /&gt;
* MDL-65249 - Redis cache store correctly displays exception after failed connections&lt;br /&gt;
* MDL-60347 - SMTP debugging no longer displayed for lower debugging output levels&lt;br /&gt;
 &lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.5.6 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.5]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.5.7]]&lt;br /&gt;
[[es:Notas de Moodle 3.5.7]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.6.5_release_notes&amp;diff=56257</id>
		<title>Moodle 3.6.5 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.6.5_release_notes&amp;diff=56257"/>
		<updated>2019-07-08T08:15:11Z</updated>

		<summary type="html">&lt;p&gt;Fox: Version officially out now&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 8 July 2019&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.6.5%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.6.5].&lt;br /&gt;
 &lt;br /&gt;
===Fixes and improvements===&lt;br /&gt;
 &lt;br /&gt;
* MDL-59650 - Calendar export no longer limited to 40 events&lt;br /&gt;
* MDL-64935 - Jump to dropdown menu no longer overlaps before / next activity links&lt;br /&gt;
* MDL-58315 - Boost theme no longer ignores HTML block custom classes &lt;br /&gt;
* MDL-53778 - Quiz with activity completion &#039;Or all available attempts completed&#039; no longer possible with unlimited attempts&lt;br /&gt;
* MDL-65101 - Users with capability moodle/site:messageanyuser can message any user regardless of their privacy settings&lt;br /&gt;
* MDL-65581 - Hidden blocks can once again be unhidden&lt;br /&gt;
* MDL-65249 - Redis cache store correctly displays exception after failed connections&lt;br /&gt;
* MDL-65084 - Recently accessed items block checks for whether a course is deleted before showing items from it&lt;br /&gt;
* MDL-57729 - Ampersand in site title no longer breaks LTI provider cartridge XML&lt;br /&gt;
* MDL-55821 - Assignment individual grading when using rubric and workflow grade is displayed&lt;br /&gt;
* MDL-65696 - PDF annotation comments no longer expand unexpectedly&lt;br /&gt;
* MDL-64784 - Enrolled users list sort order no longer changes after adding or removing a user&lt;br /&gt;
* MDL-55197 - Multi-lang filter no longer ignores &#039;en&#039; parent language&lt;br /&gt;
* MDL-65829 - Enrolments whose start date is after the analytics analysis start time are no longer discarded&lt;br /&gt;
* MDL-65641 - Texts in Moodle format remain in the same format when edited&lt;br /&gt;
* MDL-65839 - Improved memory usage of analytics evaluation and initial training processes&lt;br /&gt;
* MDL-60347 - SMTP debugging no longer displayed for lower debugging output levels&lt;br /&gt;
* MDL-65326 - Restore process no longer displays an error if the capability doesn&#039;t exist&lt;br /&gt;
* MDL-65665 - Quick reply now respects subscribe on reply user preference&lt;br /&gt;
* MDL-65814 - Item counts for action events are now shown in the timeline block&lt;br /&gt;
* MDL-65901 - Forum advanced search form styling improvements&lt;br /&gt;
* MDL-65634 - Students at risk models correctly discard user enrolments whose start and end dates do not fit into the analysed time interval&lt;br /&gt;
* MDL-65297 - Atto &#039;Manage files&#039; now detects filenames containing a hash symbol (#)&lt;br /&gt;
* MDL-65606 - Database activity unapproved entries are once again highlighted&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.6.4 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.6]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.6.5]]&lt;br /&gt;
[[es:Notas de Moodle 3.6.5]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.7.1_release_notes&amp;diff=56256</id>
		<title>Moodle 3.7.1 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.7.1_release_notes&amp;diff=56256"/>
		<updated>2019-07-08T08:14:23Z</updated>

		<summary type="html">&lt;p&gt;Fox: Version officially out now&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 8 July 2019&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.7.1%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.7.1].&lt;br /&gt;
 &lt;br /&gt;
===Fixes and improvements===&lt;br /&gt;
 &lt;br /&gt;
* MDL-59650 - Calendar export no longer limited to 40 events&lt;br /&gt;
* MDL-64935 - Jump to dropdown menu no longer overlaps before / next activity links&lt;br /&gt;
* MDL-53778 - Quiz with activity completion &#039;Or all available attempts completed&#039; no longer possible with unlimited attempts&lt;br /&gt;
* MDL-65101 - Users with capability moodle/site:messageanyuser can message any user regardless of their privacy settings&lt;br /&gt;
* MDL-65660 - Guest users prompted to enrol in order to post in a forum&lt;br /&gt;
* MDL-65675 - &#039;Re&#039; no longer duplicated in forum post subject line&lt;br /&gt;
* MDL-65249 - Redis cache store correctly displays exception after failed connections&lt;br /&gt;
* MDL-65084 - Recently accessed items block checks for whether a course is deleted before showing items from it&lt;br /&gt;
* MDL-57729 - Ampersand in site title no longer breaks LTI provider cartridge XML&lt;br /&gt;
* MDL-65655 - Forum mailings and maintenance jobs no longer fail with &#039;Suspended account&#039; exception&lt;br /&gt;
* MDL-55821 - Assignment individual grading when using rubric and workflow grade is displayed&lt;br /&gt;
* MDL-65696 - PDF annotation comments no longer expand unexpectedly&lt;br /&gt;
* MDL-64784 - Enrolled users list sort order no longer changes after adding or removing a user&lt;br /&gt;
* MDL-55197 - Multi-lang filter no longer ignores &#039;en&#039; parent language&lt;br /&gt;
* MDL-65829 - Enrolments whose start date is after the analytics analysis start time are no longer discarded&lt;br /&gt;
* MDL-65779 - Forum backup and restore retains any private replies as private&lt;br /&gt;
* MDL-65708 - Child themes have base layouts loaded&lt;br /&gt;
* MDL-65888 - Fix for &#039;error/usernotconfirmed&#039; exception in forum mailings and maintenance jobs&lt;br /&gt;
* MDL-65661 - Long course names in &#039;Recently accessed courses&#039; block correctly displayed&lt;br /&gt;
* MDL-65839 - Improved memory usage of analytics evaluation and initial training processes&lt;br /&gt;
* MDL-60347 - SMTP debugging no longer displayed for lower debugging output levels&lt;br /&gt;
* MDL-65705 - Badges from other sites which are displayed via a backpack no longer show date in the future&lt;br /&gt;
* MDL-65326 - Restore process no longer displays an error if the capability doesn&#039;t exist&lt;br /&gt;
* MDL-65665 - Quick reply now respects subscribe on reply user preference&lt;br /&gt;
* MDL-65814 - Item counts for action events are now shown in the timeline block&lt;br /&gt;
* MDL-65666 - Unread forum posts are once again highlighted&lt;br /&gt;
* MDL-65883 - Quiz navigation buttons once again scroll to the correct question on the page&lt;br /&gt;
* MDL-65901 - Forum advanced search form styling improvements&lt;br /&gt;
* MDL-65634 - Students at risk models correctly discard user enrolments whose start and end dates do not fit into the analysed time interval&lt;br /&gt;
* MDL-65297 - Atto &#039;Manage files&#039; now detects filenames containing a hash symbol (#)&lt;br /&gt;
* MDL-65591 - Language customisation page once again displays the correct buttons&lt;br /&gt;
* MDL-65606 - Database activity unapproved entries are once again highlighted&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
Details of any security issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.7 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.7]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.7.1]]&lt;br /&gt;
[[es:Notas de Moodle 3.7.1]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.7_release_notes&amp;diff=56179</id>
		<title>Moodle 3.7 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.7_release_notes&amp;diff=56179"/>
		<updated>2019-06-26T07:10:15Z</updated>

		<summary type="html">&lt;p&gt;Fox: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
Release date: 20 May 2019&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.7%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.7].&lt;br /&gt;
&lt;br /&gt;
See our [https://docs.moodle.org/37/en/New_features New features page] in the user documentation for an introduction to Moodle 3.7 with screenshots.&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from a previous version, please see [[:en:Upgrading|Upgrading]] in the user docs.&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.2 or later&lt;br /&gt;
* PHP version: minimum PHP 7.1.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.6&#039;&#039;. PHP 7.2.x and 7.3.x are supported too. PHP 7.x could have some [https://docs.moodle.org/dev/Moodle_and_PHP7#Can_I_use_PHP7_yet.3F engine limitations]. &lt;br /&gt;
* PHP extension &#039;&#039;&#039;intl&#039;&#039;&#039; is required since Moodle 3.4 (it was recommended in 2.0 onwards) &lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.4&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.6&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2008&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 11.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://whatbrowser.org&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle 3.7:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
 &lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
===Forum===&lt;br /&gt;
* MDL-22077 - Private reply option&lt;br /&gt;
* MDL-65033 - Ability to star discussions&lt;br /&gt;
* MDL-64956 - In-page forum post reply&lt;br /&gt;
* MDL-65032 - Ability to lock discussions manually&lt;br /&gt;
* MDL-65069 - Ability to create discussions without changing page&lt;br /&gt;
* MDL-64820 - Forum display updated to use templates&lt;br /&gt;
* MDL-65071 - List of discussions is sortable&lt;br /&gt;
* MDL-65034 - Accessibility improvements to forum discussions&lt;br /&gt;
* MDL-65394 - Forum rendering speed improvements&lt;br /&gt;
* MDL-46881 - Forum scheduled task (cron) has been refactored into several smaller cron tasks&lt;br /&gt;
&lt;br /&gt;
===Messaging===&lt;br /&gt;
* MDL-65015 - HTML in messages is cleaned according to site/role &amp;quot;trusttext&amp;quot; configuration&lt;br /&gt;
* MDL-64715 - Personal space in messaging drawer for draft messages etc.&lt;br /&gt;
* MDL-64495 - New settings page for messaging-related settings&lt;br /&gt;
* MDL-63620 - Group conversations can be created from both the auto-create groups edit page and the import groups tool&lt;br /&gt;
* MDL-63915 - Old messaging user interface removed and replaced with a new widget&lt;br /&gt;
* MDL-64773 - Messaging conversations can be muted&lt;br /&gt;
* MDL-65132 - New capability for deleting messages for all users within group conversations&lt;br /&gt;
* MDL-64017 - Message processors can identify and handle group messages&lt;br /&gt;
* MDL-64703 - Updated interface on the messaging index page&lt;br /&gt;
* MDL-64137 - Searches highlight text that matches the search term&lt;br /&gt;
* MDL-65114 - Timestamps in the main conversation list include days and years&lt;br /&gt;
* MDL-64093 - New admin setting to set the site default for using enter key to send messages&lt;br /&gt;
* MDL-60680 - Improved push notifications&lt;br /&gt;
&lt;br /&gt;
===Themes===&lt;br /&gt;
* MDL-58428 - All Boost templates moved to core&lt;br /&gt;
* MDL-64505 - Classic theme introduced to core&lt;br /&gt;
* MDL-64506 - Bootstrapbase and related themes (Clean/More) removed from core&lt;br /&gt;
* MDL-65449 - Themes can override the course pattern used on the dashboard&lt;br /&gt;
&lt;br /&gt;
===LTI===&lt;br /&gt;
* MDL-62599 - LTI 1.3 support introduced&lt;br /&gt;
&lt;br /&gt;
===Open Badges===&lt;br /&gt;
* MDL-63262 - Support added for Open Badges 2.0 platforms&lt;br /&gt;
* MDL-63876 - Moodle competencies can be linked to criteria for badges in Open Badges 2.0&lt;br /&gt;
&lt;br /&gt;
===Dashboard and Course Overview===&lt;br /&gt;
* MDL-63794 - Course categories can be displayed on courses in the course overview block&lt;br /&gt;
* MDL-64855 - New admin setting to control the output of the course category in the myoverview block&lt;br /&gt;
* MDL-64376 - Scrolling improved in the recently accessed courses block&lt;br /&gt;
* MDL-64903 - Course filters are logically grouped in the myoverview block&lt;br /&gt;
* MDL-64898 - The completion progress bar is no longer displayed for teachers in the myoverview block&lt;br /&gt;
&lt;br /&gt;
===Learning Analytics===&lt;br /&gt;
* MDL-61667 - Improvements to the install/uninstall procedure the Analytics API offers to plugins&lt;br /&gt;
* MDL-64783 - New “upcoming activities due” model added&lt;br /&gt;
* MDL-65582 - The &amp;quot;upcoming activities due&amp;quot; model is enabled by default&lt;br /&gt;
* MDL-64786 - Users can overwrite default model names&lt;br /&gt;
* MDL-64693 - New target added for course competencies achievement&lt;br /&gt;
* MDL-64636 - New target added for course completion&lt;br /&gt;
* MDL-65176 - New target added for students at risk of not getting the minimum grade to pass a course&lt;br /&gt;
* MDL-64954 - A &amp;quot;More info&amp;quot; link provides more information about different core analytics elements&lt;br /&gt;
* MDL-64777 - Default models can be restored&lt;br /&gt;
* MDL-64787 - Analytics models can be evaluated using a trained machine learning backend&lt;br /&gt;
* MDL-60944 - Models can be created, deleted, imported and exported&lt;br /&gt;
* MDL-64779 - Ability to choose whether to include trained model weights in an export&lt;br /&gt;
* MDL-65175 - When evaluating a model, the time-splitting method can be set using the web interface&lt;br /&gt;
* MDL-65177 - It is possible to set the frequency of insight generation for models based on assumptions (e.g. the &amp;quot;upcoming activities due&amp;quot; model)&lt;br /&gt;
* MDL-60936 - &amp;quot;Enabled time-splitting methods&amp;quot; analytics setting converted to a list of default time-splitting methods for a model&#039;s evaluation&lt;br /&gt;
&lt;br /&gt;
===Usability improvements===&lt;br /&gt;
* MDL-5311 - Choices can be cleared for single-answer multiple-choice questions&lt;br /&gt;
* MDL-43385 - Print output of books has been improved&lt;br /&gt;
* MDL-28505 - Course backup and restore can be performed asynchronously&lt;br /&gt;
* MDL-61537 - Ability to rotate pages when annotating PDFs in assignment feedback&lt;br /&gt;
* MDL-63773 - Assignment settings form hides irrelevant options instead of disabling them&lt;br /&gt;
* MDL-64552 - Moodle forms inside the admin top level directory hide irrelevant options instead of disabling them&lt;br /&gt;
* MDL-64557 - Moodle forms inside the course directory hide irrelevant options instead of disabling them&lt;br /&gt;
* MDL-60474 - The student selection tool in the grading interface reflects the sorting order of the grading table&lt;br /&gt;
* MDL-39261 - File support added to lesson essay questions&lt;br /&gt;
* MDL-60913 - Global search results can be split into tabs by category&lt;br /&gt;
* MDL-50793 - Teachers can see hidden pages in book activities&lt;br /&gt;
* MDL-60059 - Workshop activity action events support drag and drop in the calendar&lt;br /&gt;
* MDL-62142 - Accessibility improvements for Boost course landing page&lt;br /&gt;
&lt;br /&gt;
==Other Highlights==&lt;br /&gt;
&lt;br /&gt;
===Functional changes===&lt;br /&gt;
* MDL-31355 - Forum due dates are added to the calendar&lt;br /&gt;
* MDL-36088 - Adding/modifying questions to/in the question bank is logged&lt;br /&gt;
* MDL-49673 - Assignment has an option to not display the grader to students&lt;br /&gt;
* MDL-31852 - HTML tags allowed in the title of Lesson &amp;quot;content pages&amp;quot;&lt;br /&gt;
* MDL-64377 - Ability to delete assignment file submissions&lt;br /&gt;
* MDL-64243 - Nextcloud serves &amp;quot;offline&amp;quot; files consistent with other integrations (e.g. OneDrive and Google Docs)&lt;br /&gt;
* MDL-53346 - User competencies in courses show the linked learning plans&lt;br /&gt;
* MDL-62223 - Improved submission statements for assignments&lt;br /&gt;
* MDL-52828 - Competencies can be graded when grading an activity&lt;br /&gt;
* MDL-65154 - Course competencies page shows students which competencies are linked to an activity&lt;br /&gt;
* MDL-64414 - &amp;quot;AND&amp;quot; and &amp;quot;OR&amp;quot; are available in if-conditions for grade calculations&lt;br /&gt;
&lt;br /&gt;
===For administrators===&lt;br /&gt;
* MDL-10965 - There is a new capability available to view the list of non-hidden courses&lt;br /&gt;
* MDL-57898 - New custom field types plugin and course custom fields functionality&lt;br /&gt;
* MDL-49399 - Output can be captured during cron and task runs&lt;br /&gt;
* MDL-62869 - Global search can be configured to include all visible courses&lt;br /&gt;
* MDL-64322 - New data privacy capability to restrict submission of deletion requests for other users&lt;br /&gt;
* MDL-63569 - A constant can be added to the subject of all emails &lt;br /&gt;
* MDL-62907 - The standard log table &#039;other&#039; field can be set to store in JSON format&lt;br /&gt;
* MDL-64281 - Frame embedding is always allowed for requests coming from the Moodle app &lt;br /&gt;
* MDL-61164 - Tasks using legacy cron functionality moved to scheduled tasks&lt;br /&gt;
* MDL-57900 - Added fields to provide site metadata to support learning analytics&lt;br /&gt;
* MDL-63623 - Plugins can be uninstalled via command line&lt;br /&gt;
* MDL-64323 - Additional fields are included in user searches when making new data requests on behalf of a user&lt;br /&gt;
* MDL-64347 - Improved processing of scheduled and ad-hoc tasks&lt;br /&gt;
* MDL-65142 - Tables can be downloaded in PDF format (new dataformat)&lt;br /&gt;
* MDL-64314 - Insights notification enable web notifications by default&lt;br /&gt;
* MDL-65138 - Course sharing to Moodle.net is disabled by default (configured via a new setting)&lt;br /&gt;
* MDL-64454 - Site administration page warns if cron does not run frequently&lt;br /&gt;
* MDL-62728 - The language packs page displays a warning when locales are not fully supported&lt;br /&gt;
* MDL-64071 - Improved diagnostics when testing LDAP settings&lt;br /&gt;
* MDL-64823 - Disabling mobile plugins works as expected&lt;br /&gt;
* MDL-44484 - Theme field available in the bulk upload users tool&lt;br /&gt;
* MDL-64477 - Learning analytics usage data is included with site usage data&lt;br /&gt;
* MDL-64337 - Mobile app enabled sites prompt users that do not use the app to download it in notification emails&lt;br /&gt;
* MDL-64339 - User names provided in the comments report are hyperlinked to the user&#039;s profile&lt;br /&gt;
&lt;br /&gt;
==For developers==&lt;br /&gt;
* MDL-54592 - MongoDB cache store upgraded to use PHP 7 compatible library&lt;br /&gt;
* MDL-63977 - Behat testing available for mobile app features and plugins&lt;br /&gt;
* MDL-63986 - Behat testing added for the messaging drawer&lt;br /&gt;
* MDL-64449 - New debug feature to expose code issues with session locks&lt;br /&gt;
* MDL-52167 - Core functionality added to enable site administration settings to be hidden if dependent on another disabled setting&lt;br /&gt;
* MDL-63366 - Ability to specify filters for unit testing coverage&lt;br /&gt;
* MDL-65130 - Improved unit testing coverage generation by only respecting the @covers annotation&lt;br /&gt;
* MDL-60470 - New &amp;quot;after_require_login&amp;quot; hook introduced &lt;br /&gt;
* MDL-65204 - Phpunit upgraded to version 7.5.x&lt;br /&gt;
* MDL-64348 - Improved AJAX template fetching&lt;br /&gt;
* MDL-59986 - External database enrolment sync moved to a scheduled task&lt;br /&gt;
* MDL-63880 - Some templates common in dashboard blocks have been moved to increase reusability&lt;br /&gt;
* MDL-64587 - New option in the XMLDB editor to add the mandatory persistent fields&lt;br /&gt;
* MDL-64324 - ID collisions are avoided when forms are loaded from AJAX&lt;br /&gt;
* MDL-64684 - When JavaScript caching is disabled, jQuery and RequireJS are no longer minified&lt;br /&gt;
&lt;br /&gt;
===New web services===&lt;br /&gt;
* MDL-64252 - New SCORM web service to return user capabilities&lt;br /&gt;
* MDL-64656 - New web service to return the tag associated with an element&lt;br /&gt;
* MDL-64655 - New forum web service to return user access information&lt;br /&gt;
* MDL-64642 - New web service to call multiple external functions&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.6 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.7]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.7]]&lt;br /&gt;
[[es:Notas de Moodle 3.7]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Overview&amp;diff=55886</id>
		<title>Overview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Overview&amp;diff=55886"/>
		<updated>2019-04-05T12:56:53Z</updated>

		<summary type="html">&lt;p&gt;Fox: Improvments and LTS&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;A lot of people ask how the development of Moodle operates. This page should give you a working overview that should help in understanding a lot of other developer documentation.&lt;br /&gt;
&lt;br /&gt;
==The key players==&lt;br /&gt;
&lt;br /&gt;
;Martin Dougiamas: Martin is the founder lead developer of Moodle. Generally he tries to facilitate democracy and meritocracy but occasionally has to make executive decisions on things.&lt;br /&gt;
&lt;br /&gt;
;[https://moodle.com/careers/ Moodle HQ]: The team of more than 20 developers who are directly funded by the Moodle project to work full-time on core developments.&lt;br /&gt;
&lt;br /&gt;
;Moodle Partners: Over 50 companies around the world that provide Moodle services. These companies often have their own developers and may contribute to Moodle directly by working on core code or by creating plugins.&lt;br /&gt;
&lt;br /&gt;
;Component leads: A number of people around the world have volunteered to lead various components in Moodle. This involves maintaining existing code as well as listening to the community and improving that component with new features.&lt;br /&gt;
&lt;br /&gt;
There are many other people contributing to Moodle in many ways. For a full list see the [http://moodle.org/local/dev/ Moodle developers] page on moodle.org.&lt;br /&gt;
&lt;br /&gt;
==How we develop the Roadmap==&lt;br /&gt;
&lt;br /&gt;
The [[Roadmap]] lists the new features being developed for the next major version. This list is derived mostly from the issues with large numbers of votes in the Moodle [[Tracker]], so please vote for what you want!  Other influences include general discussion, surveys and feature requests at Moodle Moots and in the Moodle forums.&lt;br /&gt;
&lt;br /&gt;
Component leads decide on features in individual components so make your case to them!&lt;br /&gt;
&lt;br /&gt;
==Moodle versions==&lt;br /&gt;
&lt;br /&gt;
Moodle major releases (with big new features) are on a regular 6 month cycle, in  May and November, since Moodle 2.6. Each major release increments the version number by 0.1 (eg 3.4 -&amp;gt; 3.5 -&amp;gt; 3.6)) and starts a new branch of minor releases.&lt;br /&gt;
&lt;br /&gt;
Minor releases (with bug fixes only) are on a 2 month cycle, unless a security emergency occurs. They will increment the major release by 0.0.1 (eg 3.5 -&amp;gt; 3.5.1 -&amp;gt; 3.5.2).   &lt;br /&gt;
&lt;br /&gt;
The full details of these can be seen in the [[Releases]].&lt;br /&gt;
&lt;br /&gt;
==Support lifetime==&lt;br /&gt;
&lt;br /&gt;
Moodle HQ is committed to supporting major releases for 12 months of general fixes (usually 6 point releases) and 18 months (an additional 6 months) of security fixes.&lt;br /&gt;
&lt;br /&gt;
That means we usually release minor versions for the last three major branches.&lt;br /&gt;
&lt;br /&gt;
Some versions, each two years, are long term supported (LTS) for a total of 36 months, with 18 additional months of security fixes compared to other versions.&lt;br /&gt;
&lt;br /&gt;
==Issue tracking==&lt;br /&gt;
&lt;br /&gt;
Issue tracking is an important part of a continuous quality control process. It involves reporting of problems (bugs), ideas for improvement and new features. Unlike most proprietary software programs, Moodle issue reporting and tracking information is open to everyone. Moodle&#039;s issue tracking system is called the [http://tracker.moodle.org/ Tracker].&lt;br /&gt;
&lt;br /&gt;
All Moodle users are encouraged to be active participants when it comes to testing. Anyone with a Tracker user account can create, view, comment on, vote, and watch bugs.&lt;br /&gt;
&lt;br /&gt;
==Processes==&lt;br /&gt;
&lt;br /&gt;
As you might guess, a large software project like Moodle with hundreds of contributors and varied opinions can be difficult to manage.&lt;br /&gt;
&lt;br /&gt;
Over time we have developed a number of well-defined processes for getting code in and out of Moodle and for governing everyone&#039;s workflow in a way that is fair and clear.&lt;br /&gt;
&lt;br /&gt;
See our [[Process]] document for full information on our development processes, including how you can contribute to the project.&lt;br /&gt;
&lt;br /&gt;
==Coding Standards==&lt;br /&gt;
&lt;br /&gt;
Over time we have distilled our best practice in writing code down into our [[Coding|Coding Guide]].  These rules cover the formatting and layout of all our code to make it consistent across the code base. If you plan to write Moodle code, you need to read it thoroughly. &lt;br /&gt;
&lt;br /&gt;
==Plugins and APIs==&lt;br /&gt;
&lt;br /&gt;
Although Moodle is open source and you can change anything you want, the best and most maintainable way to extend Moodle is to write a plugin (sometimes called a module). Plugins are a directory of code that can be simply &amp;quot;dropped&amp;quot; in into any Moodle installation and it will be detected, installed and automatically made available as a tool within the Moodle interface. &lt;br /&gt;
&lt;br /&gt;
See our [[Plugins|Plugin documentation]] for full details of the various types of plugin available.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Finding your way into the Moodle code]]&lt;br /&gt;
* [[Working with the Community]]&lt;br /&gt;
* [[Plugin contribution]]&lt;br /&gt;
* [http://www.slideshare.net/poltawski/how-to-guarantee-your-change-is-integrated-to-moodle-core How to guarantee your change is integrated to Moodle core] presentation by Dan Poltawski &lt;br /&gt;
&lt;br /&gt;
[[Category:Quality Assurance|Overview]]&lt;br /&gt;
[[Category:Processes|Overview]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_App_Plugins_Development_Guide&amp;diff=55835</id>
		<title>Moodle App Plugins Development Guide</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_App_Plugins_Development_Guide&amp;diff=55835"/>
		<updated>2019-03-28T10:33:33Z</updated>

		<summary type="html">&lt;p&gt;Fox: Typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle Mobile}}&lt;br /&gt;
{{Moodle Mobile 3.5}}&lt;br /&gt;
&lt;br /&gt;
==Before 3.5==&lt;br /&gt;
&lt;br /&gt;
Since Moodle 3.1 Moodle plugins could be supported in the Mobile app, but only by writing an Angular JS/Ionic module, compiling it to a zip, and including that in your plugin. See [[Moodle Mobile Remote add-ons|Remote add-ons]] for details.&lt;br /&gt;
&lt;br /&gt;
In Moodle 3.5 the app switched to a new way to support plugins that was much easier for developers.&lt;br /&gt;
* This new way will allow developers to support plugins using PHP code, templates and Ionic markup (html components).&lt;br /&gt;
* The use of JavaScript is optional (but some type of advanced plugins may require it)&lt;br /&gt;
* Developers won’t need to set up a Mobile development environment, they will be able to test using the latest version of the official app (although setting up a local Mobile environment is recommended for complex plugins).&lt;br /&gt;
&lt;br /&gt;
This means that remote add-ons won’t be necessary anymore, and developers won’t have to learn Ionic 3 / Angular and set up a new mobile development environment to migrate them. Plugins using the old Remote add-ons mechanism will have to be migrated to the new simpler way (following this documentation)&lt;br /&gt;
&lt;br /&gt;
This new way is natively supported in Moodle 3.5. For previous versions you will need to install the Moodle Mobile Additional Features plugin.&lt;br /&gt;
&lt;br /&gt;
==How it works==&lt;br /&gt;
&lt;br /&gt;
The overall idea is to allow Moodle plugins to extend different areas in the app with &#039;&#039;just PHP server side&#039;&#039; code and Ionic 3 markup (custom html elements that are called components) using a set of custom Ionic directives and components.&lt;br /&gt;
&lt;br /&gt;
Developers will have to:&lt;br /&gt;
# Create a db/mobile.php file in their plugins. In this file developers will be able to indicate which areas of the app they want to extend, for example, adding a new option in the main menu, implementing an activity module not supported, including a new option in the course menu, including a new option in the user profile, etc. All the areas supported are described further in this document.&lt;br /&gt;
# Create new functions in a reserved namespace that will return the content of the new options. The content should be returned rendered (html). The template should use [https://ionicframework.com/docs/components/ Ionic components] so that it looks native (custom html elements) but it can be generated using mustache templates. &lt;br /&gt;
&lt;br /&gt;
Let’s clarify some points:&lt;br /&gt;
&lt;br /&gt;
* You don’t need to create new Web Service functions (although you will be able to use them for advanced features). You just need plain php functions that will be placed in a reserved namespace.&lt;br /&gt;
* Those functions will be exported via the Web Service function tool_mobile_get_content&lt;br /&gt;
* As arguments of your functions you will always receive the userid, some relevant details of the app (app version, current language in the app, etc…) and some specific data depending on the type of plugin (courseid, cmid, …).&lt;br /&gt;
* We provide a list of custom Ionic components and directives (html tags) that will provide dynamic behaviour, like indicating that you are linking a file that can be downloaded, or to allow a transition to new pages into the app calling a specific function in the server, submit form data to the server  etc..&lt;br /&gt;
&lt;br /&gt;
==Types of plugins==&lt;br /&gt;
&lt;br /&gt;
We could classify all the plugins in 3 different types:&lt;br /&gt;
&lt;br /&gt;
===Templates generated and downloaded when the user opens the plugins===&lt;br /&gt;
&lt;br /&gt;
[[File:Templates_downloaded_when_requested.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
With this type of plugin, the template of your plugin will be generated and downloaded when the user opens your plugin in the app. This means that your function will receive some context params. For example, if you&#039;re developing a course module plugin you will receive the courseid and the cmid (course module ID). You can see the list of delegates that support this type of plugin in the [[Mobile_support_for_plugins#Delegates|Delegates]] section.&lt;br /&gt;
&lt;br /&gt;
===Templates downloaded on login and rendered using JS data===&lt;br /&gt;
&lt;br /&gt;
[[File:Templates_downloaded_on_login.png|thumb]]&lt;br /&gt;
&lt;br /&gt;
With this type of plugin, the template for your plugin will be downloaded when the user logins in the app and will be stored in the device. This means that your function will not receive any context params, and you need to return a generic template that will be built with JS data like the ones in the Mobile app. When the user opens a page that includes your plugin, your template will receive the required JS data and your template will be rendered. You can see the list of delegates that support this type of plugin in the [[Mobile_support_for_plugins#Delegates|Delegates]] section.&lt;br /&gt;
&lt;br /&gt;
===Pure Javascript plugins===&lt;br /&gt;
&lt;br /&gt;
You can always implement your whole plugin yourself using Javascript instead of using our API. In fact, this is required if you want to implement some features like capturing links in the Mobile app. You can see the list of delegates that only support this type of plugin in the [[Mobile_support_for_plugins#Delegates|Delegates]] section.&lt;br /&gt;
&lt;br /&gt;
==Step by step example==&lt;br /&gt;
&lt;br /&gt;
In this example, we are going to update an existing plugin ([https://github.com/markn86/moodle-mod_certificate Certificate activity module]) that currently uses a Remote add-on.&lt;br /&gt;
This is a simple activity module that displays the certificate issued for the current user along with the list of the dates of previously issued certificates. It also stores in the course log that the user viewed a certificate. This module also works offline: when the user downloads the course or activity, the data is pre-fetched and can be viewed offline.&lt;br /&gt;
&lt;br /&gt;
The example code can be downloaded from here (https://github.com/markn86/moodle-mod_certificate/commit/003fbac0d80fd96baf428255500980bf95a7a0d6)&lt;br /&gt;
&lt;br /&gt;
TIP: Make sure to ([https://docs.moodle.org/35/en/Developer_tools#Purge_all_caches purge all cache]) after making an edit to one of the following files for your changes to be taken into account.&lt;br /&gt;
&lt;br /&gt;
===Step 1. Update the db/mobile.php file===&lt;br /&gt;
In this case, we are updating an existing file but for new plugins, you should create this new file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$addons = [&lt;br /&gt;
    &#039;mod_certificate&#039; =&amp;gt; [ // Plugin identifier&lt;br /&gt;
        &#039;handlers&#039; =&amp;gt; [ // Different places where the plugin will display content.&lt;br /&gt;
            &#039;coursecertificate&#039; =&amp;gt; [ // Handler unique name (alphanumeric).&lt;br /&gt;
                &#039;displaydata&#039; =&amp;gt; [&lt;br /&gt;
                    &#039;icon&#039; =&amp;gt; $CFG-&amp;gt;wwwroot . &#039;/mod/certificate/pix/icon.gif&#039;,&lt;br /&gt;
                    &#039;class&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
                ],&lt;br /&gt;
       &lt;br /&gt;
                &#039;delegate&#039; =&amp;gt; &#039;CoreCourseModuleDelegate&#039;, // Delegate (where to display the link to the plugin)&lt;br /&gt;
                &#039;method&#039; =&amp;gt; &#039;mobile_course_view&#039;, // Main function in \mod_certificate\output\mobile&lt;br /&gt;
                &#039;offlinefunctions&#039; =&amp;gt; [&lt;br /&gt;
                    &#039;mobile_course_view&#039; =&amp;gt; [],&lt;br /&gt;
                    &#039;mobile_issues_view&#039; =&amp;gt; [],&lt;br /&gt;
                ]. // Function that needs to be downloaded for offline.&lt;br /&gt;
            ],&lt;br /&gt;
        ],&lt;br /&gt;
        &#039;lang&#039; =&amp;gt; [ // Language strings that are used in all the handlers.&lt;br /&gt;
            [&#039;pluginname&#039;, &#039;certificate&#039;],&lt;br /&gt;
            [&#039;summaryofattempts&#039;, &#039;certificate&#039;],&lt;br /&gt;
            [&#039;getcertificate&#039;, &#039;certificate&#039;],&lt;br /&gt;
            [&#039;requiredtimenotmet&#039;, &#039;certificate&#039;],&lt;br /&gt;
            [&#039;viewcertificateviews&#039;, &#039;certificate&#039;],&lt;br /&gt;
        ],&lt;br /&gt;
    ],&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Plugin identifier:&lt;br /&gt;
: A unique name for the plugin, it can be anything (there’s no need to match the module name).&lt;br /&gt;
 &lt;br /&gt;
;Handlers  (Different places where the plugin will display content):&lt;br /&gt;
: A plugin can be displayed in different views in the app. Each view should have a unique name inside the plugin scope (alphanumeric).&lt;br /&gt;
&lt;br /&gt;
; Display data:&lt;br /&gt;
: This is only needed for certain types of plugins. Also, depending on the type of delegate it may require additional (or less fields), in this case we are indicating the module icon.&lt;br /&gt;
	&lt;br /&gt;
; Delegate&lt;br /&gt;
: Where to display the link to the plugin, see the Delegates chapter in this documentation for all the possible options.&lt;br /&gt;
&lt;br /&gt;
; Method:&lt;br /&gt;
: This is the method in the Moodle \(component)\output\mobile class to be executed the first time the user clicks in the new option displayed in the app.	&lt;br /&gt;
&lt;br /&gt;
; Offlinefunctions&lt;br /&gt;
: These are the functions that need to be downloaded for offline usage. This is the list of functions that need to be called and stored when the user downloads a course for offline usage. Please note that you can add functions here that are not even listed in the mobile.php file. &lt;br /&gt;
: In our example, downloading for offline access will mean that we&#039;ll execute the functions for getting the certificate and issued certificates passing as parameters the current userid (and courseid when we are using the mod or course delegate). If we have the result of those functions stored in the app, we&#039;ll be able to display the certificate information even if the user is offline.&lt;br /&gt;
: Offline functions will be mostly used to display information for final users, any further interaction with the view won’t be supported offline (for example, trying to send information when the user is offline).&lt;br /&gt;
: You can indicate here other Web Services functions, indicating the parameters that they might need from a defined subset (currently userid and courseid)&lt;br /&gt;
: Prefetching the module will also download all the files returned by the methods in these offline functions (in the &#039;&#039;files&#039;&#039; array).&lt;br /&gt;
: Note: If your functions use additional custom parameters (for example, if you implement multiple pages within a module&#039;s view function by using a &#039;page&#039; parameter in addition to the usual cmid, courseid, userid) then the app will not know which additional parameters to supply. In this case, do not list the function in offlinefunctions; instead, you will need to manually implement a [[#Module_prefetch_handler|module prefetch handler]].&lt;br /&gt;
&lt;br /&gt;
;Lang:&lt;br /&gt;
: The language pack string ids used in the plugin by all the handlers. Normally these will be strings from your own plugin, however, you can list any strings you need here (e.g. [&#039;cancel&#039;, &#039;moodle&#039;]).&lt;br /&gt;
: Please only include the strings you actually need. The Web Service that returns the plugin information will include the translation of each string id for every language installed in the platform, and this will then be cached, so listing too many strings is very wasteful.&lt;br /&gt;
&lt;br /&gt;
There are additional attributes supported by the mobile.php list, see “Mobile.php supported options” section below.&lt;br /&gt;
&lt;br /&gt;
===Step 2. Creating the main function===&lt;br /&gt;
&lt;br /&gt;
The main function displays the current issued certificate (or several warnings if it’s not possible to issue a certificate). It also displays a link to view the dates of previously issued certificates.&lt;br /&gt;
&lt;br /&gt;
All the functions must be created in the plugin or subsystem classes/output directory, the name of the class must be mobile.&lt;br /&gt;
&lt;br /&gt;
For this example (mod_certificate plugin) the namespace name will be mod_certificate\output.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/classes/output/mobile.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
namespace mod_certificate\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use context_module;&lt;br /&gt;
use mod_certificate_external;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Mobile output class for certificate&lt;br /&gt;
 *&lt;br /&gt;
 * @package    mod_certificate&lt;br /&gt;
 * @copyright  2018 Juan Leyva&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
class mobile {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the certificate course view for the mobile app.&lt;br /&gt;
     * @param  array $args Arguments from tool_mobile_get_content WS&lt;br /&gt;
     *&lt;br /&gt;
     * @return array       HTML, javascript and otherdata&lt;br /&gt;
     */&lt;br /&gt;
    public static function mobile_course_view($args) {&lt;br /&gt;
        global $OUTPUT, $USER, $DB;&lt;br /&gt;
&lt;br /&gt;
        $args = (object) $args;&lt;br /&gt;
        $cm = get_coursemodule_from_id(&#039;certificate&#039;, $args-&amp;gt;cmid);&lt;br /&gt;
&lt;br /&gt;
        // Capabilities check.&lt;br /&gt;
        require_login($args-&amp;gt;courseid , false , $cm, true, true);&lt;br /&gt;
&lt;br /&gt;
        $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
        require_capability (&#039;mod/certificate:view&#039;, $context);&lt;br /&gt;
        if ($args-&amp;gt;userid != $USER-&amp;gt;id) {&lt;br /&gt;
            require_capability(&#039;mod/certificate:manage&#039;, $context);&lt;br /&gt;
        }&lt;br /&gt;
        $certificate = $DB-&amp;gt;get_record(&#039;certificate&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;instance));&lt;br /&gt;
&lt;br /&gt;
        // Get certificates from external (taking care of exceptions).&lt;br /&gt;
        try {&lt;br /&gt;
            $issued = mod_certificate_external::issue_certificate($cm-&amp;gt;instance);&lt;br /&gt;
            $certificates = mod_certificate_external::get_issued_certificates($cm-&amp;gt;instance);&lt;br /&gt;
            $issues = array_values($certificates[&#039;issues&#039;]); // Make it mustache compatible.&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $issues = array();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        // Set timemodified for each certificate.&lt;br /&gt;
        foreach ($issues as $issue) {&lt;br /&gt;
            if (empty($issue-&amp;gt;timemodified)) {&lt;br /&gt;
                    $issue-&amp;gt;timemodified = $issue-&amp;gt;timecreated;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $showget = true;&lt;br /&gt;
        if ($certificate-&amp;gt;requiredtime &amp;amp;&amp;amp; !has_capability(&#039;mod/certificate:manage&#039;, $context)) {&lt;br /&gt;
            if (certificate_get_course_time($certificate-&amp;gt;course) &amp;lt; ($certificate-&amp;gt;requiredtime * 60)) {&lt;br /&gt;
                    $showget = false;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $certificate-&amp;gt;name = format_string($certificate-&amp;gt;name);&lt;br /&gt;
        list($certificate-&amp;gt;intro, $certificate-&amp;gt;introformat) =&lt;br /&gt;
                        external_format_text($certificate-&amp;gt;intro, $certificate-&amp;gt;introformat, $context-&amp;gt;id,&#039;mod_certificate&#039;, &#039;intro&#039;);&lt;br /&gt;
        $data = array(&lt;br /&gt;
            &#039;certificate&#039; =&amp;gt; $certificate,&lt;br /&gt;
            &#039;showget&#039; =&amp;gt; $showget &amp;amp;&amp;amp; count($issues) &amp;gt; 0,&lt;br /&gt;
            &#039;issues&#039; =&amp;gt; $issues,&lt;br /&gt;
            &#039;issue&#039; =&amp;gt; $issues[0],&lt;br /&gt;
            &#039;numissues&#039; =&amp;gt; count($issues),&lt;br /&gt;
            &#039;cmid&#039; =&amp;gt; $cm-&amp;gt;id,&lt;br /&gt;
            &#039;courseid&#039; =&amp;gt; $args-&amp;gt;courseid&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        return [&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; [&lt;br /&gt;
                [&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
                ],&lt;br /&gt;
            ],&lt;br /&gt;
            &#039;javascript&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
            &#039;otherdata&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
            &#039;files&#039; =&amp;gt; $issues,&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let’s go through the function code to analyse the different parts.&lt;br /&gt;
&lt;br /&gt;
;Function declaration: &lt;br /&gt;
: The function name is the same as the one used in the mobile.php file (method field). There is only one argument “$args” which is an array containing all the information sent by the mobile app (the courseid, userid, appid, appversionname, appversioncode, applang, appcustomurlscheme…)&lt;br /&gt;
&lt;br /&gt;
; Function implementation:&lt;br /&gt;
: In the first part of the function, we check permissions and capabilities (like a view.php script would do normally). Then we retrieve the certificate information that’s necessary to display the template.&lt;br /&gt;
&lt;br /&gt;
Finally, we return:&lt;br /&gt;
* The rendered template (notice that we could return more than one template but we usually would only need one). By default the app will always render the first template received, the rest of the templates can be used if the plugin defines some Javascript code.&lt;br /&gt;
* JavaScript: Empty, because we don’t need any in this case&lt;br /&gt;
* Other data: Empty as well, because we don’t need any additional data to be used by directives or components in the template. This field will be published as an object supporting 2-way-data-bind to the template.&lt;br /&gt;
* Files: A list of files that the app should be able to download (for offline usage mostly)&lt;br /&gt;
&lt;br /&gt;
===Step 3. Creating the template for the main function===&lt;br /&gt;
&lt;br /&gt;
This is the most important part of your plugin because it contains the code that will be rendered on the mobile app.&lt;br /&gt;
&lt;br /&gt;
In this template we’ll be using Ionic and custom directives and components available in the Mobile app.&lt;br /&gt;
&lt;br /&gt;
All the HTML attributes starting with ion- are ionic components. Most of the time the component name is self-explanatory but you may refer to a detailed guide here: https://ionicframework.com/docs/components/ &lt;br /&gt;
&lt;br /&gt;
All the HTML attributes starting with &#039;&#039;core-&#039;&#039; are custom components of the Mobile app.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/templates/mobile_view_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{=&amp;lt;% %&amp;gt;=}}&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
    &amp;lt;core-course-module-description description=&amp;quot;&amp;lt;% certificate.intro %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-course-module-description&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;ion-list&amp;gt;&lt;br /&gt;
        &amp;lt;ion-list-header&amp;gt;&lt;br /&gt;
            &amp;lt;p class=&amp;quot;item-heading&amp;quot;&amp;gt;{{ &#039;plugin.mod_certificate.summaryofattempts&#039; | translate }}&amp;lt;/p&amp;gt;&lt;br /&gt;
        &amp;lt;/ion-list-header&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;%#issues%&amp;gt;&lt;br /&gt;
            &amp;lt;ion-item&amp;gt;&lt;br /&gt;
                &amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-new-content title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
                    {{ &#039;plugin.mod_certificate.viewcertificateviews&#039; | translate: {$a: &amp;lt;% numissues %&amp;gt;} }}&lt;br /&gt;
                &amp;lt;/button&amp;gt;&lt;br /&gt;
            &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;%/issues%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;%#showget%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-item&amp;gt;&lt;br /&gt;
            &amp;lt;button ion-button block core-course-download-module-main-file moduleId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot; courseId=&amp;quot;&amp;lt;% certificate.course %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; [files]=&amp;quot;[{fileurl: &#039;&amp;lt;% issue.fileurl %&amp;gt;&#039;, filename: &#039;&amp;lt;% issue.filename %&amp;gt;&#039;, timemodified: &#039;&amp;lt;% issue.timemodified %&amp;gt;&#039;, mimetype: &#039;&amp;lt;% issue.mimetype %&amp;gt;&#039;}]&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;ion-icon name=&amp;quot;cloud-download&amp;quot; item-start&amp;gt;&amp;lt;/ion-icon&amp;gt;&lt;br /&gt;
                {{ &#039;plugin.mod_certificate.getcertificate&#039; | translate }}&lt;br /&gt;
            &amp;lt;/button&amp;gt;&lt;br /&gt;
        &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;%/showget%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;%^showget%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-item&amp;gt;&lt;br /&gt;
            &amp;lt;p&amp;gt;{{ &#039;plugin.mod_certificate.requiredtimenotmet&#039; | translate }}&amp;lt;/p&amp;gt;&lt;br /&gt;
        &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;%/showget%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        &amp;lt;!-- Call log WS when the template is loaded. --&amp;gt;&lt;br /&gt;
        &amp;lt;span core-site-plugins-call-ws-on-load name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the first line of the template we switch delimiters to avoid conflicting with Ionic delimiters (that are curly brackets like mustache). &lt;br /&gt;
&lt;br /&gt;
Then we display the module description using &amp;lt;code&amp;gt;&amp;lt;core-course-module-description&amp;lt;/code&amp;gt; that is a component used to include the course module description.&lt;br /&gt;
&lt;br /&gt;
For displaying the certificate information we create a list of elements, adding a header on top.&lt;br /&gt;
The following line &amp;lt;code&amp;gt;{{ &#039;plugin.mod_certificate.summaryofattempts&#039; | translate }}&amp;lt;/code&amp;gt; indicates that the Mobile app will translate the &#039;&#039;summaryofattempts&#039;&#039; string id (here we could’ve used mustache translation but it is usually better to delegate the strings translations to the app). The string id has this format: &lt;br /&gt;
&lt;br /&gt;
“plugin” + plugin identifier (from mobile.php) +  string id (the string must be indicated in the lang field in mobile.php). &lt;br /&gt;
&lt;br /&gt;
Then we display a button to transition to another page if there are certificates issued. The attribute (directive) &amp;lt;code&amp;gt;core-site-plugins-new-content&amp;lt;/code&amp;gt; indicates that if the user clicks the button, we need to call the function “mobile_issues_view” in the component “mod_certificate” passing as arguments the cmid and courseid. The content returned by this function will be displayed in a new page (see Step 4 for the code of this new page).&lt;br /&gt;
&lt;br /&gt;
Just after this button we display another one but this time for downloading an issued certificate. The &amp;lt;code&amp;gt;core-course-download-module-main-file&amp;lt;/code&amp;gt; directive indicates that clicking this button is for downloading the whole activity and opening the main file. This means that, when the user clicks this button, the whole certificate activity will be available in offline.&lt;br /&gt;
&lt;br /&gt;
Finally, just before the ion-list is closed, we use the &amp;lt;code&amp;gt;core-site-plugins-call-ws-on-load&amp;lt;/code&amp;gt; directive to indicate that once the page is loaded, we need to call to a Web Service function in the server, in this case we are calling the &#039;&#039;mod_certificate_view_certificate&#039;&#039; that will log that the user viewed this page.&lt;br /&gt;
&lt;br /&gt;
As you can see, no JavaScript was necessary at all. We used plain HTML elements and attributes that did all the complex dynamic logic (like calling a Web Service) behind the scenes.&lt;br /&gt;
&lt;br /&gt;
===Step 4. Adding an additional page===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Partial file contents: mod/certificate/classes/output/mobile.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Returns the certificate issues view for the mobile app.&lt;br /&gt;
     * @param  array $args Arguments from tool_mobile_get_content WS&lt;br /&gt;
     *&lt;br /&gt;
     * @return array       HTML, javascript and otherdata&lt;br /&gt;
     */&lt;br /&gt;
    public static function mobile_issues_view($args) {&lt;br /&gt;
        global $OUTPUT, $USER, $DB;&lt;br /&gt;
&lt;br /&gt;
        $args = (object) $args;&lt;br /&gt;
        $cm = get_coursemodule_from_id(&#039;certificate&#039;, $args-&amp;gt;cmid);&lt;br /&gt;
&lt;br /&gt;
        // Capabilities check.&lt;br /&gt;
        require_login($args-&amp;gt;courseid , false , $cm, true, true);&lt;br /&gt;
&lt;br /&gt;
        $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
        require_capability (&#039;mod/certificate:view&#039;, $context);&lt;br /&gt;
        if ($args-&amp;gt;userid != $USER-&amp;gt;id) {&lt;br /&gt;
            require_capability(&#039;mod/certificate:manage&#039;, $context);&lt;br /&gt;
        }&lt;br /&gt;
        $certificate = $DB-&amp;gt;get_record(&#039;certificate&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;instance));&lt;br /&gt;
&lt;br /&gt;
        // Get certificates from external (taking care of exceptions).&lt;br /&gt;
        try {&lt;br /&gt;
            $issued = mod_certificate_external::issue_certificate($cm-&amp;gt;instance);&lt;br /&gt;
            $certificates = mod_certificate_external::get_issued_certificates($cm-&amp;gt;instance);&lt;br /&gt;
            $issues = array_values($certificates[&#039;issues&#039;]); // Make it mustache compatible.&lt;br /&gt;
        } catch (Exception $e) {&lt;br /&gt;
            $issues = array();&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $data = [&lt;br /&gt;
            &#039;issues&#039; =&amp;gt; $issues&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        return [&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; [&lt;br /&gt;
                [&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_issues&#039;, $data),&lt;br /&gt;
                ],&lt;br /&gt;
            ],&lt;br /&gt;
            &#039;javascript&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
            &#039;otherdata&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function for the new page was added just after the mobile_course_view function, the code is quite similar: Capabilities checks, retrieves the information required for the template and returns the template rendered.&lt;br /&gt;
&lt;br /&gt;
The code of the mustache template is also very simple:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/templates/mobile_view_issues.mustache&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code xml&amp;gt;&lt;br /&gt;
{{=&amp;lt;% %&amp;gt;=}}&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
    &amp;lt;ion-list&amp;gt;&lt;br /&gt;
        &amp;lt;%#issues%&amp;gt;&lt;br /&gt;
            &amp;lt;ion-item&amp;gt;&lt;br /&gt;
                &amp;lt;p class=&amp;quot;item-heading&amp;quot;&amp;gt;{{ &amp;lt;%timecreated%&amp;gt; | coreToLocaleString }}&amp;lt;/p&amp;gt;&lt;br /&gt;
                &amp;lt;p&amp;gt;&amp;lt;%grade%&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
            &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;%/issues%&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As we did in the previous template, in the first line of the template we switch delimiters to avoid conflicting with Ionic delimiters (that are curly brackets like mustache). &lt;br /&gt;
&lt;br /&gt;
Here we are creating an ionic list that will display a new item in the list per each issued certificated.&lt;br /&gt;
&lt;br /&gt;
For the issued certificated we’ll display the time when it was created (using the app filter &#039;&#039;coreToLocaleString&#039;&#039;). We are also displaying the grade displayed in the certificate (if any).&lt;br /&gt;
&lt;br /&gt;
===Step 5. Plugin webservices, if included===&lt;br /&gt;
&lt;br /&gt;
If your plugin uses its own web services, they will also need to be enabled for mobile access in your db/services.php file.&lt;br /&gt;
&lt;br /&gt;
The following line &amp;lt;code&amp;gt;&#039;services&#039;      =&amp;gt; [MOODLE_OFFICIAL_MOBILE_SERVICE, &#039;local_mobile&#039;],&amp;lt;/code&amp;gt; should be included in each webservice definition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/db/services.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$functions = [&lt;br /&gt;
&lt;br /&gt;
    &#039;mod_certificate_get_certificates_by_courses&#039; =&amp;gt; [&lt;br /&gt;
        &#039;classname&#039;     =&amp;gt; &#039;mod_certificate_external&#039;,&lt;br /&gt;
        &#039;methodname&#039;    =&amp;gt; &#039;get_certificates_by_courses&#039;,&lt;br /&gt;
        &#039;description&#039;   =&amp;gt; &#039;Returns a list of certificate instances...&#039;,&lt;br /&gt;
        &#039;type&#039;          =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;capabilities&#039;  =&amp;gt; &#039;mod/certificate:view&#039;,&lt;br /&gt;
        &#039;services&#039;      =&amp;gt; [MOODLE_OFFICIAL_MOBILE_SERVICE, &#039;local_mobile&#039;],&lt;br /&gt;
    ],&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
	&lt;br /&gt;
This extra services definition is the reason why you will need to have the local_mobile plugin installed for Moodle versions 3.4 and lower, so that your Moodle site will have all the additional webservices included to deal with all these mobile access calls. This is explained further in the [https://docs.moodle.org/dev/Mobile_support_for_plugins#Moodle_version_requirements Moodle version requirements section] below.&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
The first and most important thing to know is that you don’t need a local mobile environment, you can just use the Chrome or Chromium browser to add mobile support to your plugins!&lt;br /&gt;
&lt;br /&gt;
Open this URL (with Chrome or Chromium browser): https://mobileapp.moodledemo.net/ and you will see a web version of the mobile app completely functional (except for some native features). This URL is updated with the latest integration version of the app.&lt;br /&gt;
&lt;br /&gt;
Please test that your site works correctly in the web version before starting any development.&lt;br /&gt;
&lt;br /&gt;
===Moodle version requirements===&lt;br /&gt;
&lt;br /&gt;
If your Moodle version is lower than 3.5 you will need to install the [https://docs.moodle.org/en/Moodle_Mobile_additional_features Moodle Mobile additional features plugin]. &lt;br /&gt;
&lt;br /&gt;
Please use this development version for now: https://github.com/moodlehq/moodle-local_mobile/commits/MOODLE_31_STABLE (if your Moodle version is 3.2, 3.3 or 3.4) you will have to use the specific branch for your version but applying manually the [https://github.com/moodlehq/moodle-local_mobile/commits/MOODLE_31_STABLE last commit from the 3.1 branch] (the one with number MOBILE-2362).&lt;br /&gt;
&lt;br /&gt;
Also, when installing the Moodle Mobile Additional features plugin you must follow the installation instructions so the service is set up properly.&lt;br /&gt;
&lt;br /&gt;
Remember to update your plugin documentation to reflect that this plugin is mandatory for Mobile support. We don’t recommend to indicate in your plugin version.php a dependency to local_mobile though.&lt;br /&gt;
&lt;br /&gt;
===Development workflow===&lt;br /&gt;
&lt;br /&gt;
First of all, we recommend creating a simple &#039;&#039;mobile.php&#039;&#039; for displaying a new main menu option (even if your plugin won’t be in the main menu, just to verify that you are able to extend the app plugins). Then open the webapp (https://mobileapp.moodledemo.net/) or refresh the browser if it was already open. Check that you can correctly  see the new menu option you included.&lt;br /&gt;
&lt;br /&gt;
Then, develop the main function of the app returning a “Hello world” or basic code (without using templates) to see that everything works together. After adding the classes/output/mobile.php file it is very important to “Purge all caches” to avoid problems with the auto-loading cache.&lt;br /&gt;
&lt;br /&gt;
It is important to remember that:&lt;br /&gt;
* Any change in the mobile.php file will require you to refresh the web app page in the browser (remember to disable the cache in the Chrome developer options).&lt;br /&gt;
* Any change in an existing template or function won’t require to refresh the browser page. In most cases you should just do a PTR (Pull down To Refresh) in the page that displays the view returned by the function. Be aware that PTR will work only when using the “device” emulation in the browser (see following section).&lt;br /&gt;
&lt;br /&gt;
===Testing and debugging===&lt;br /&gt;
&lt;br /&gt;
To learn how to debug with the web version of the app, please read the following documents:&lt;br /&gt;
* [[Moodle Mobile debugging WS requests]] AND&lt;br /&gt;
* [[Moodle Mobile development using Chrome or Chromium]] (please, omit the installation section)&lt;br /&gt;
&lt;br /&gt;
For plugins using the Javascript API you may develop making use of the console.log function to add trace messages in your code that will be displayed in the browser console.&lt;br /&gt;
&lt;br /&gt;
Within the app, make sure to turn on the option: &#039;&#039;&#039;App settings&#039;&#039;&#039; / &#039;&#039;&#039;General&#039;&#039;&#039; / &#039;&#039;&#039;Display debug messages&#039;&#039;&#039;. This means popup errors from the app will show more information.&lt;br /&gt;
&lt;br /&gt;
==Mobile.php supported options==&lt;br /&gt;
&lt;br /&gt;
In the Step by Step section we learned about some of the existing options for handlers configuration. This is the full list of supported options:&lt;br /&gt;
&lt;br /&gt;
===Common options===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;delegate&#039;&#039;&#039; (mandatory): Name of the delegate to register the handler in.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (mandatory): The function to call to retrieve the main page content.&lt;br /&gt;
* &#039;&#039;&#039;init&#039;&#039;&#039; (optional): A function to call to retrieve the initialization JS and the &amp;quot;restrict&amp;quot; to apply to the whole handler. It can also return templates that can be used from the Javascript of the init method or the Javascript of the handler’s method.&lt;br /&gt;
* &#039;&#039;&#039;restricttocurrentuser&#039;&#039;&#039; (optional) Only used if the delegate has a isEnabledForUser function. If true, the handler will only be shown for current user. For more info about displaying the plugin only for certain users, please see [[Mobile_support_for_plugins#Display_the_plugin_only_if_certain_conditions_are_met|Display the plugin only if certain conditions are met]].&lt;br /&gt;
* &#039;&#039;&#039;restricttoenrolledcourses&#039;&#039;&#039; (optional): Only used if the delegate has a isEnabledForCourse function. If true or not defined, the handler will only be shown for courses the user is enrolled in. For more info about displaying the plugin only for certain courses, please see [[Mobile_support_for_plugins#Display_the_plugin_only_if_certain_conditions_are_met|Display the plugin only if certain conditions are met]].&lt;br /&gt;
* &#039;&#039;&#039;styles&#039;&#039;&#039; (optional): An array with two properties: &#039;&#039;url&#039;&#039; and &#039;&#039;version&#039;&#039;. The URL should point to a CSS file, either using an absolute URL or a relative URL. This file will be downloaded and applied by the app. It&#039;s recommended to include styles that will only affect your plugin templates. The version number is used to determine if the file needs to be downloaded again, you should change the version number everytime you change the CSS file.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreCourseOptionsDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory): title, class.&lt;br /&gt;
* &#039;&#039;&#039;priority&#039;&#039;&#039; (optional): Priority of the handler. Higher priority is displayed first. &lt;br /&gt;
&lt;br /&gt;
===Options only for CoreMainMenuDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory): title, icon, class.&lt;br /&gt;
* &#039;&#039;&#039;priority&#039;&#039;&#039; (optional): Priority of the handler. Higher priority is displayed first. Main Menu plugins are always displayed in the &amp;quot;More&amp;quot; tab, they cannot be displayed as tabs in the bottom bar.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreCourseModuleDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory): icon, class.&lt;br /&gt;
* &#039;&#039;&#039;offlinefunctions&#039;&#039;&#039;: (optional) List of functions to call when prefetching the module. It can be a get_content method or a WS. You can filter the params received by the WS. By default, WS will receive these params: courseid, cmid, userid. Other valid values that will be added if they are present in the list of params: courseids (it will receive a list with the courses the user is enrolled in), component + &#039;id&#039; (e.g. certificateid).&lt;br /&gt;
* &#039;&#039;&#039;downloadbutton&#039;&#039;&#039;: (optional) Whether to display download button in the module. If not defined, the button will be shown if there is any offlinefunction.&lt;br /&gt;
* &#039;&#039;&#039;isresource&#039;&#039;&#039;: (optional) Whether the module is a resource or an activity. Only used if there is any offlinefunction. If your module relies on the &amp;quot;contents&amp;quot; field, then it should be true.&lt;br /&gt;
* &#039;&#039;&#039;updatesnames&#039;&#039;&#039;: (optional) Only used if there is any offlinefunction. A Regular Expression to check if there&#039;s any update in the module. It will be compared to the result of &#039;&#039;core_course_check_updates&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;displayopeninbrowser&#039;&#039;&#039;: (optional) Supported from the 3.6 version of the app. Whether the module should display the &amp;quot;Open in browser&amp;quot; option in the top-right menu. This can be done in JavaScript too: this.displayOpenInBrowser = false;&lt;br /&gt;
* &#039;&#039;&#039;displaydescription&#039;&#039;&#039;: (optional) Supported from the 3.6 version of the app. Whether the module should display the &amp;quot;Description&amp;quot; option in the top-right menu. This can be done in JavaScript too: this.displayDescription = false;&lt;br /&gt;
* &#039;&#039;&#039;displayrefresh&#039;&#039;&#039;: (optional) Supported from the 3.6 version of the app. Whether the module should display the &amp;quot;Refresh&amp;quot; option in the top-right menu. This can be done in JavaScript too: this.displayRefresh = false;&lt;br /&gt;
* &#039;&#039;&#039;displayprefetch&#039;&#039;&#039;: (optional) Supported from the 3.6 version of the app. Whether the module should display the download option in the top-right menu. This can be done in JavaScript too: this.displayPrefetch = false;&lt;br /&gt;
* &#039;&#039;&#039;displaysize&#039;&#039;&#039;: (optional) Supported from the 3.6 version of the app. Whether the module should display the downloaded size in the top-right menu. This can be done in JavaScript too: this.displaySize = false;&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreCourseFormatDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;canviewallsections&#039;&#039;&#039;: (optional) Whether the course format allows seeing all sections in a single page. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;displayenabledownload&#039;&#039;&#039;: (optional) Whether the option to enable section/module download should be displayed. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;displaysectionselector&#039;&#039;&#039;: (optional) Whether the default section selector should be displayed. Defaults to true.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreUserDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory): title, icon, class.&lt;br /&gt;
* &#039;&#039;&#039;type&#039;&#039;&#039;: The type of the addon. Values accepted: &#039;newpage&#039; (default) or  &#039;communication&#039;. &lt;br /&gt;
* &#039;&#039;&#039;priority&#039;&#039;&#039; (optional): Priority of the handler. Higher priority is displayed first. &lt;br /&gt;
&lt;br /&gt;
===Options only for CoreSettingsDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory): title, icon, class.&lt;br /&gt;
* &#039;&#039;&#039;priority&#039;&#039;&#039; (optional): Priority of the handler. Higher priority is displayed first. &lt;br /&gt;
&lt;br /&gt;
===Options only for AddonMessageOutputDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory): title, icon.&lt;br /&gt;
* &#039;&#039;&#039;priority&#039;&#039;&#039; (optional): Priority of the handler. Higher priority is displayed first. &lt;br /&gt;
&lt;br /&gt;
==Delegates==&lt;br /&gt;
&lt;br /&gt;
The delegates can be classified by type of plugin. For more info about type of plugins, please see the See [[Mobile_support_for_plugins#Types_of_plugins|Types of plugins]] section.&lt;br /&gt;
&lt;br /&gt;
===Templates generated and downloaded when the user opens the plugins===&lt;br /&gt;
&lt;br /&gt;
====CoreMainMenuDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add new items to the main menu (currently displayed at the bottom of the app). &lt;br /&gt;
&lt;br /&gt;
====CoreCourseOptionsDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add new options in a course (Participants or Grades are examples of this type of delegate).&lt;br /&gt;
&lt;br /&gt;
====CoreCourseModuleDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting activity modules or resources.&lt;br /&gt;
&lt;br /&gt;
====CoreUserDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add additional options in the user profile page in the app.&lt;br /&gt;
&lt;br /&gt;
====CoreCourseFormatDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting course formats.&lt;br /&gt;
&lt;br /&gt;
====CoreSettingsDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate to add a new option in the settings page.&lt;br /&gt;
&lt;br /&gt;
====AddonMessageOutputDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate to support a message output plugin.&lt;br /&gt;
&lt;br /&gt;
===Templates downloaded on login and rendered using JS data===&lt;br /&gt;
&lt;br /&gt;
====CoreQuestionDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting question types.&lt;br /&gt;
https://docs.moodle.org/dev/Creating_mobile_question_types&lt;br /&gt;
&lt;br /&gt;
====CoreQuestionBehaviourDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting question behaviours.&lt;br /&gt;
&lt;br /&gt;
====CoreUserProfileFieldDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting user profile fields.&lt;br /&gt;
&lt;br /&gt;
====AddonModQuizAccessRuleDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate to support a quiz access rule.&lt;br /&gt;
&lt;br /&gt;
====AddonModAssignSubmissionDelegate and AddonModAssignFeedbackDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use these delegates to support assign submission or feedback plugins.&lt;br /&gt;
&lt;br /&gt;
====AddonWorkshopAssessmentStrategyDelegate====&lt;br /&gt;
&lt;br /&gt;
You must use this delegate to support a workshop assessment strategy plugin.&lt;br /&gt;
&lt;br /&gt;
===Pure Javascript plugins===&lt;br /&gt;
&lt;br /&gt;
These delegates require JavaScript to be supported. See [[Mobile_support_for_plugins#Initialization|Initialization]] for more information.&lt;br /&gt;
&lt;br /&gt;
* CoreContentLinksDelegate&lt;br /&gt;
* CoreCourseModulePrefetchDelegate&lt;br /&gt;
* CoreFileUploaderDelegate&lt;br /&gt;
* CorePluginFileDelegate&lt;br /&gt;
&lt;br /&gt;
==Available components and directives==&lt;br /&gt;
&lt;br /&gt;
===Difference between component and directives===&lt;br /&gt;
&lt;br /&gt;
A component (represented as an HTML tag) is used to add custom elements to the app.&lt;br /&gt;
Example of components are: ion-list, ion-item, core-search-box&lt;br /&gt;
&lt;br /&gt;
A directive (represented as an HTML attribute) allows you to extend a piece of HTML with additional information or functionality.&lt;br /&gt;
Example of directives are: core-auto-focus, *ngIf, ng-repeat&lt;br /&gt;
&lt;br /&gt;
The Mobile app uses Angular, Ionic and custom components and directives, for a full reference of:&lt;br /&gt;
* Angular directives, please check: https://angular.io/api?type=directive&lt;br /&gt;
* Ionic components, please check: https://ionicframework.com/docs/&lt;br /&gt;
&lt;br /&gt;
===Custom core components and directives===&lt;br /&gt;
&lt;br /&gt;
These are some useful custom components and directives (only available in the mobile app). Please notice that this isn’t the full list of components and directives of the app, it’s just an extract of the most common ones.&lt;br /&gt;
&lt;br /&gt;
====core-format-text====&lt;br /&gt;
&lt;br /&gt;
This directive formats the text and adds some directives needed for the app to work as it should. For example, it treats all links and all the embedded media so they work fine in the app. If some content in your template includes links or embedded media, please use this directive.&lt;br /&gt;
&lt;br /&gt;
This directive automatically applies core-external-content and core-link to all the links and embedded media.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;text&#039;&#039;&#039; (string): The text to format.&lt;br /&gt;
* &#039;&#039;&#039;siteId&#039;&#039;&#039; (string): Optional. Site ID to use. If not defined, current site.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to use when downloading embedded files.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
* &#039;&#039;&#039;adaptImg&#039;&#039;&#039; (boolean): Optional. Whether to adapt images to screen width. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;clean&#039;&#039;&#039; (boolean): Optional. Whether all the HTML tags should be removed. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;singleLine&#039;&#039;&#039; (boolean): Optional. Whether new lines should be removed (all text in single line). Only if clean=true. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;maxHeight&#039;&#039;&#039; (number): Optional. Max height in pixels to render the content box. It should be 50 at least to make sense. Using this parameter will force display: block to calculate height better. If you want to avoid this use class=&amp;quot;inline&amp;quot; at the same time to use display: inline-block.&lt;br /&gt;
* &#039;&#039;&#039;fullOnClick&#039;&#039;&#039; (boolean): Optional. Whether it should open a new page with the full contents on click. Only if maxHeight is set and the content has been collapsed. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;fullTitle&#039;&#039;&#039; (string): Optional. Title to use in full view. Defaults to &amp;quot;Description&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-format-text text=&amp;quot;&amp;lt;% cm.description %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-format-text&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-link====&lt;br /&gt;
&lt;br /&gt;
Directive to handle a link. It performs several checks, like checking if the link needs to be opened in the app, and opens the link as it should (without overriding the app).&lt;br /&gt;
&lt;br /&gt;
This directive is automatically applied to all the links and media inside core-format-text.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;capture&#039;&#039;&#039; (boolean): Optional. Whether the link needs to be captured by the app (check if the link can be handled by the app instead of opening it in a browser).&lt;br /&gt;
* &#039;&#039;&#039;inApp&#039;&#039;&#039; (boolean): Optional. True to open in embedded browser, false to open in system browser.&lt;br /&gt;
* &#039;&#039;&#039;autoLogin&#039;&#039;&#039; (string): Optional. If the link should be open with auto-login. Accepts the following values:&lt;br /&gt;
** &amp;quot;yes&amp;quot; -&amp;gt; Always auto-login.&lt;br /&gt;
** &amp;quot;no&amp;quot; -&amp;gt; Never auto-login.&lt;br /&gt;
** &amp;quot;check&amp;quot; -&amp;gt; Auto-login only if it points to the current site. Default value.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;&amp;lt;% cm.url %&amp;gt;&amp;quot; core-link&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-external-content====&lt;br /&gt;
&lt;br /&gt;
Directive to handle links to files and embedded files. This directive should be used in any link to a file or any embedded file that you want to have available when the app is offline. &lt;br /&gt;
&lt;br /&gt;
If a file is downloaded, its URL will be replaced by the local file URL.&lt;br /&gt;
&lt;br /&gt;
This directive is automatically applied to all the links and media inside core-format-text.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;siteId&#039;&#039;&#039; (string): Optional. Site ID to use. If not defined, current site.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to use when downloading embedded files.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;img src=&amp;quot;&amp;lt;% event.iconurl %&amp;gt;&amp;quot; core-external-content component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% event.id %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-user-link====&lt;br /&gt;
&lt;br /&gt;
Directive to go to user profile on click. When the user clicks the element where this directive is attached, the right user profile will be opened.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;userId&#039;&#039;&#039; (number): User id to open the profile.&lt;br /&gt;
* &#039;&#039;&#039;courseId&#039;&#039;&#039; (number): Optional. Course id to show the user info related to that course.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;a ion-item core-user-link userId=&amp;quot;&amp;lt;% userid %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-file====&lt;br /&gt;
&lt;br /&gt;
Component to handle a remote file. It shows the file name, icon (depending on mimetype) and a button to download/refresh it. The user can identify if the file is downloaded or not based on the button.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* file (object): The file. Must have a property &#039;filename&#039; and a &#039;fileurl&#039; or &#039;url&#039;&lt;br /&gt;
* component (string): Optional. Component the file belongs to.&lt;br /&gt;
* componentId (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
* canDelete (boolean): Optional. Whether file can be deleted.&lt;br /&gt;
* alwaysDownload (boolean): Optional. Whether it should always display the refresh button when the file is downloaded. Use it for files that you cannot determine if they&#039;re outdated or not.&lt;br /&gt;
* canDownload (boolean): Optional. Whether file can be downloaded. Defaults to true.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-file [file]=&amp;quot;{fileurl: &#039;&amp;lt;% issue.url %&amp;gt;&#039;, filename: &#039;&amp;lt;% issue.name %&amp;gt;&#039;, timemodified: &#039;&amp;lt;% issue.timemodified %&amp;gt;&#039;, filesize: &#039;&amp;lt;% issue.size %&amp;gt;&#039;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-file&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-download-file====&lt;br /&gt;
&lt;br /&gt;
Directive to allow downloading and open a file. When the item with this directive is clicked, the file will be downloaded (if needed) and opened.&lt;br /&gt;
&lt;br /&gt;
It is usually recommended to use the core-file component since it also displays the state of the file.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;core-download-file&#039;&#039;&#039; (object): The file to download.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to link the file to.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. Component ID to use in conjunction with the component.&lt;br /&gt;
&lt;br /&gt;
Example usage: a button to download a file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button [core-download-file]=&amp;quot;{fileurl: &amp;lt;% issue.url %&amp;gt;, timemodified: &amp;lt;% issue.timemodified %&amp;gt;, filesize: &amp;lt;% issue.size %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.download | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-course-download-module-main-file====&lt;br /&gt;
&lt;br /&gt;
Directive to allow downloading and opening the main file of a module.&lt;br /&gt;
&lt;br /&gt;
When the item with this directive is clicked, the whole module will be downloaded (if needed) and its main file opened. This is meant for modules like mod_resource.&lt;br /&gt;
&lt;br /&gt;
This directive must receive either a module or a moduleId. If no files are provided, it will use module.contents.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;module&#039;&#039;&#039; (object): Optional. The module object. Required if module is not supplied.&lt;br /&gt;
* &#039;&#039;&#039;moduleId&#039;&#039;&#039; (number): Optional. The module ID. Required if module is not supplied.&lt;br /&gt;
* &#039;&#039;&#039;courseId&#039;&#039;&#039; (number): The course ID the module belongs to.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to link the file to.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. Component ID to use in conjunction with the component. If not defined, moduleId.&lt;br /&gt;
* &#039;&#039;&#039;files&#039;&#039;&#039; (object[]): Optional. List of files of the module. If not provided, use module.contents.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block core-course-download-module-main-file moduleId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot; courseId=&amp;quot;&amp;lt;% certificate.course %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; [files]=&amp;quot;[{fileurl: &#039;&amp;lt;% issue.fileurl %&amp;gt;&#039;, filename: &#039;&amp;lt;% issue.filename %&amp;gt;&#039;, timemodified: &#039;&amp;lt;% issue.timemodified %&amp;gt;&#039;, mimetype: &#039;&amp;lt;% issue.mimetype %&amp;gt;&#039;}]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getcertificate&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-navbar-buttons====&lt;br /&gt;
&lt;br /&gt;
Component to add buttons to the app&#039;s header without having to place them inside the header itself. Using this component in a site plugin will allow adding buttons to the header of the current page.&lt;br /&gt;
&lt;br /&gt;
If this component indicates a position (start/end), the buttons will only be added if the header has some buttons in that position. If no start/end is specified, then the buttons will be added to the first &amp;lt;ion-buttons&amp;gt; found in the header.&lt;br /&gt;
&lt;br /&gt;
You can use the [hidden] input to hide all the inner buttons if a certain condition is met.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-navbar-buttons end&amp;gt;&lt;br /&gt;
    &amp;lt;button ion-button icon-only (click)=&amp;quot;action()&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ion-icon name=&amp;quot;funnel&amp;quot;&amp;gt;&amp;lt;/ion-icon&amp;gt;&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/core-navbar-buttons&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can also use this to add options to the context menu. Example usage:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-navbar-buttons&amp;gt;&lt;br /&gt;
    &amp;lt;core-context-menu&amp;gt;&lt;br /&gt;
        &amp;lt;core-context-menu-item [priority]=&amp;quot;500&amp;quot; [content]=&amp;quot;&#039;Nice boat&#039;&amp;quot; (action)=&amp;quot;boatFunction()&amp;quot; [iconAction]=&amp;quot;&#039;boat&#039;&amp;quot;&amp;gt;&amp;lt;/core-context-menu-item&amp;gt;&lt;br /&gt;
    &amp;lt;/core-context-menu&amp;gt;&lt;br /&gt;
&amp;lt;/core-navbar-buttons&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that it is not currently possible to remove or modify options from the context menu without using a nasty hack.&lt;br /&gt;
&lt;br /&gt;
===Specific component and directives for plugins===&lt;br /&gt;
&lt;br /&gt;
These are component and directives created specifically for supporting Moodle plugins.&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-new-content====&lt;br /&gt;
&lt;br /&gt;
Directive to display a new content when clicked. This new content can be displayed in a new page or in the current page (only if the current page is already displaying a site plugin content).&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): The component of the new content.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (string): The method to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;args&#039;&#039;&#039; (object): The params to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call of the new content: whether to use cache or not, etc. This field was added in v3.6.0.&lt;br /&gt;
* &#039;&#039;&#039;title&#039;&#039;&#039; (string): The title to display with the new content. Only if samePage=false.&lt;br /&gt;
* &#039;&#039;&#039;samePage&#039;&#039;&#039; (boolean): Whether to display the content in same page or open a new one. Defaults to new page.&lt;br /&gt;
* &#039;&#039;&#039;useOtherData&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the args for the new &#039;&#039;get_content&#039;&#039; call. The format is the same as in &#039;&#039;useOtherDataForWS&#039;&#039;. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the new &#039;&#039;get_content&#039;&#039; WS call. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to go to a new content page:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-new-content title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.viewissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to load new content in current page using userid from otherdata:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-new-content component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot; samePage=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.viewissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS when the element is clicked. The action to do when the WS call is successful depends on the provided data: display a message, go back or refresh current view.&lt;br /&gt;
&lt;br /&gt;
If you want to load a new content when the WS call is done, please see core-site-plugins-call-ws-new-content.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
* &#039;&#039;&#039;confirmMessage&#039;&#039;&#039; (string): Message to confirm the action when the user clicks the element. If not supplied, no confirmation. If supplied but empty, default message (&amp;quot;Are you sure?&amp;quot;).&lt;br /&gt;
* &#039;&#039;&#039;showError&#039;&#039;&#039; (boolean): Whether to show an error message if the WS call fails. Defaults to true. This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;successMessage&#039;&#039;&#039; (string): Message to show on success. If not supplied, no message. If supplied but empty, default message (“Success”).&lt;br /&gt;
* &#039;&#039;&#039;goBackOnSuccess&#039;&#039;&#039; (boolean): Whether to go back if the WS call is successful.&lt;br /&gt;
* &#039;&#039;&#039;refreshOnSuccess&#039;&#039;&#039; (boolean): Whether to refresh the current view if the WS call is successful.&lt;br /&gt;
* &#039;&#039;&#039;onSuccess&#039;&#039;&#039; (Function): A function to call when the WS call is successful (HTTP call successful and no exception returned). This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;onError&#039;&#039;&#039; (Function): A function to call when the WS call fails (HTTP call fails or an exception is returned). This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;onDone&#039;&#039;&#039; (Function): A function to call when the WS call finishes (either success or fail). This field was added in v3.5.2.&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to send some data to the server without using cache, displaying default messages and refreshing on success:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot; confirmMessage successMessage refreshOnSuccess=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.senddata&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to send some data to the server using cache without confirming, going back on success and using userid from otherdata:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; goBackOnSuccess=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.senddata&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same example as the previous one but implementing a custom JS code to run on success:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot; (onSuccess)=&amp;quot;certificateViewed($event)&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.senddata&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.certificateViewed = function(result) {&lt;br /&gt;
    // Code to run when the WS call is successful.&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws-new-content====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS when the element is clicked and load a new content passing the WS result as args. This new content can be displayed in a new page or in the same page (only if current page is already displaying a site plugin content).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t need to load some new content when done, please see core-site-plugins-call-ws.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
* &#039;&#039;&#039;confirmMessage&#039;&#039;&#039; (string): Message to confirm the action when the user clicks the element. If not supplied, no confirmation. If supplied but empty, default message (&amp;quot;Are you sure?&amp;quot;).&lt;br /&gt;
* &#039;&#039;&#039;showError&#039;&#039;&#039; (boolean): Whether to show an error message if the WS call fails. Defaults to true. This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): The component of the new content.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (string): The method to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;args&#039;&#039;&#039; (object): The params to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;title&#039;&#039;&#039; (string): The title to display with the new content. Only if samePage=false.&lt;br /&gt;
* &#039;&#039;&#039;samePage&#039;&#039;&#039; (boolean): Whether to display the content in same page or open a new one. Defaults to new page.&lt;br /&gt;
* &#039;&#039;&#039;useOtherData&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the args for the new &#039;&#039;get_content&#039;&#039; call. The format is the same as in &#039;&#039;useOtherDataForWS&#039;&#039;.&lt;br /&gt;
* &#039;&#039;&#039;jsData&#039;&#039;&#039; (any): JS variables to pass to the new page so they can be used in the template or JS. If true is supplied instead of an object, all initial variables from current page will be copied. This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;newContentPreSets&#039;&#039;&#039; (object): Extra options for the WS call of the new content: whether to use cache or not, etc. This field was added in v3.6.0.&lt;br /&gt;
* &#039;&#039;&#039;onSuccess&#039;&#039;&#039; (Function): A function to call when the WS call is successful (HTTP call successful and no exception returned). This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;onError&#039;&#039;&#039; (Function): A function to call when the WS call fails (HTTP call fails or an exception is returned). This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;onDone&#039;&#039;&#039; (Function): A function to call when the WS call finishes (either success or fail). This field was added in v3.5.2.&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to get some data from the server without using cache, showing default confirm and displaying a new page:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws-new-content name=&amp;quot;mod_certificate_get_issued_certificates&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot; confirmMessage title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to get some data from the server using cache, without confirm, displaying new content in same page and using &#039;&#039;userid&#039;&#039; from &#039;&#039;otherdata&#039;&#039;:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws-new-content name=&amp;quot;mod_certificate_get_issued_certificates&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot; samePage=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Same example as the previous one but implementing a custom JS code to run on success:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws-new-content name=&amp;quot;mod_certificate_get_issued_certificates&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot; samePage=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot; (onSuccess)=&amp;quot;callDone($event)&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.callDone = function(result) {&lt;br /&gt;
    // Code to run when the WS call is successful.&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws-on-load====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS as soon as the template is loaded. This directive is meant for actions to do in the background, like calling logging Web Services.&lt;br /&gt;
&lt;br /&gt;
If you want to call a WS when the user clicks on a certain element, please see core-site-plugins-call-ws.&lt;br /&gt;
&lt;br /&gt;
Note that this will cause an error to appear on each page load if the user is offline in v3.5.1 and older, the bug was fixed in v3.5.2.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins#Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
* &#039;&#039;&#039;onSuccess&#039;&#039;&#039; (Function): A function to call when the WS call is successful (HTTP call successful and no exception returned). This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;onError&#039;&#039;&#039; (Function): A function to call when the WS call fails (HTTP call fails or an exception is returned). This field was added in v3.5.2.&lt;br /&gt;
* &#039;&#039;&#039;onDone&#039;&#039;&#039; (Function): A function to call when the WS call finishes (either success or fail). This field was added in v3.5.2.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;span core-site-plugins-call-ws-on-load name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot; (onSuccess)=&amp;quot;callDone($event)&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.callDone = function(result) {&lt;br /&gt;
    // Code to run when the WS call is successful.&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Advanced features==&lt;br /&gt;
&lt;br /&gt;
===Display the plugin only if certain conditions are met===&lt;br /&gt;
&lt;br /&gt;
You might want to display your plugin in the mobile app only if certain dynamic conditions are met, so the plugin would be displayed only for some users. This can be achieved using the &amp;quot;init&amp;quot; method (for more info, please see the [[Mobile_support_for_plugins#Initialization|Initialization]] section ahead).&lt;br /&gt;
&lt;br /&gt;
All the init methods are called as soon as your plugin is retrieved. If you don&#039;t want your plugin to be displayed for the current user, then you should return an exception in this init method. It&#039;s recommended to include a message explaining why the plugin isn&#039;t available for the current user, this exception will be logged in the Javascript console.&lt;br /&gt;
&lt;br /&gt;
On the other hand, you might want to display a plugin only for certain courses (&#039;&#039;CoreCourseOptionsDelegate&#039;&#039;) or only if the user is viewing certain users&#039; profiles (&#039;&#039;CoreUserDelegate&#039;&#039;). This can be achieved with the init method too.&lt;br /&gt;
&lt;br /&gt;
In the init method you can return a &amp;quot;restrict&amp;quot; property with two fields in it: &#039;&#039;courses&#039;&#039; and &#039;&#039;users&#039;&#039;. If you return a list of courses IDs in this restrict property, then your plugin will only be displayed when the user views any of those courses. In the same way, if you return a list of user IDs then your plugin will only be displayed when the user views any of those users&#039; profiles.&lt;br /&gt;
&lt;br /&gt;
===Using “otherdata”===&lt;br /&gt;
&lt;br /&gt;
The values returned by the functions in otherdata are added to a variable so they can be used both in Javascript and in templates. The otherdata returned by a init call is added to a variable named INIT_OTHERDATA, while the otherdata returned by a &#039;&#039;get_content&#039;&#039; WS call is added to a variable named CONTENT_OTHERDATA.&lt;br /&gt;
&lt;br /&gt;
The otherdata returned by a init call will be passed to the JS and template of all the get_content calls in that handler. The otherdata returned by a get_content call will only be passed to the JS and template returned by that get_content call.&lt;br /&gt;
&lt;br /&gt;
This means that, in your Javascript, you can access and use these data like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
this.CONTENT_OTHERDATA.myVar&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
And in the template you could use it like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
{{ CONTENT_OTHERDATA.myVar }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;myVar&#039;&#039; is the name we put to one of our variables, it can be the name you want. In the example above, this is the otherdata returned by the PHP method:&lt;br /&gt;
&lt;br /&gt;
array(&#039;myVar&#039; =&amp;gt; &#039;Initial value&#039;)&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
In our plugin we want to display an input text with a certain initial value. When the user clicks a button, we want the value in the input to be sent to a certain WebService. This can be done using otherdata.&lt;br /&gt;
&lt;br /&gt;
We will return the initial value of the input in the otherdata of our PHP method:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;myVar&#039; =&amp;gt; &#039;My initial value&#039;),&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Then in the template we will use it like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-item text-wrap&amp;gt;&lt;br /&gt;
    &amp;lt;ion-label stacked&amp;gt;{{ &#039;plugin.mod_certificate.textlabel | translate }}&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
    &amp;lt;ion-input type=&amp;quot;text&amp;quot; [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.myVar&amp;quot;&amp;gt;&amp;lt;/ion-input&amp;gt;&lt;br /&gt;
&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;ion-item&amp;gt;&lt;br /&gt;
    &amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-call-ws name=&amp;quot;mod_certificate_my_webservice&amp;quot; [useOtherDataForWS]=&amp;quot;[&#039;myVar&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
        {{ &#039;plugin.mod_certificate.send | translate }}&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are creating an input text and we use &#039;&#039;[(ngModel)]&#039;&#039; to use the value in &#039;&#039;myVar&#039;&#039; as the initial value and to store the changes in the same &#039;&#039;myVar&#039;&#039; variable. This means that the initial value of the input will be “My initial value”, and if the user changes the value of the input these changes will be applied to the &#039;&#039;myVar&#039;&#039; variable. This is called 2-way data binding in Angular.&lt;br /&gt;
&lt;br /&gt;
Then we add a button to send this data to a WS, and for that we use the directive core-site-plugins-call-ws. We use the &#039;&#039;useOtherDataForWS&#039;&#039; attribute to specify which variable from &#039;&#039;otherdata&#039;&#039; we want to send to our WebService. So if the user enters “A new value” in the input and then clicks the button, it will call the WebService &#039;&#039;mod_certificate_my_webservice&#039;&#039; and will send as a param: myVar -&amp;gt; “A new value”.&lt;br /&gt;
&lt;br /&gt;
We can achieve the same result using the &#039;&#039;params&#039;&#039; attribute of the core-site-plugins-call-ws directive instead of using &#039;&#039;useOtherDataForWS&#039;&#039;:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-call-ws name=&amp;quot;mod_certificate_my_webservice&amp;quot; [params]=&amp;quot;{myVar: CONTENT_OTHERDATA.myVar}&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.send | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The WebService call will be exactly the same with both buttons.&lt;br /&gt;
&lt;br /&gt;
Please notice that this example could be done without using otherdata too, using the “&#039;&#039;form&#039;&#039;” input of the &#039;&#039;core-site-plugins-call-ws directive&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Running JS code after a content template has loaded===&lt;br /&gt;
&lt;br /&gt;
When you return JavaScript code from a handler function using the &#039;javascript&#039; array key, this code is executed immediately after the web service call returns, which may be before the returned template has been rendered into the DOM. &lt;br /&gt;
&lt;br /&gt;
If your code needs to run after the DOM has been updated, you can use setTimeout to call it. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
return [&lt;br /&gt;
    &#039;template&#039; =&amp;gt; [ ... ],&lt;br /&gt;
    &#039;javascript&#039; =&amp;gt; &#039;setTimeout(function() { console.log(&amp;quot;DOM is available now&amp;quot;); });&#039;,&lt;br /&gt;
    &#039;otherdata&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
    &#039;files&#039; =&amp;gt; []&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: If you wanted to write a lot of code here, you might be better off putting it in a function defined in the response from an init template, so that it does not get loaded again with each page of content.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
===JS functions visible in the templates===&lt;br /&gt;
&lt;br /&gt;
The app provides some Javascript functions that can be used from the templates to update, refresh or view content. These are the functions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;openContent(title: string, args: any, component?: string, method?: string)&#039;&#039;&#039;: Open a new page to display some new content. You need to specify the &#039;&#039;title&#039;&#039; of the new page and the &#039;&#039;args&#039;&#039; to send to the method. If &#039;&#039;component&#039;&#039; and &#039;&#039;method&#039;&#039; aren&#039;t provided, it will use the same as in the current page.&lt;br /&gt;
* &#039;&#039;&#039;refreshContent(showSpinner = true)&#039;&#039;&#039;: Refresh the current content. By default it will display a spinner while refreshing, if you don&#039;t want it to be displayed you should pass false as a parameter.&lt;br /&gt;
* &#039;&#039;&#039;updateContent(args: any, component?: string, method?: string)&#039;&#039;&#039;: Refresh the current content using different params. You need to specify the &#039;&#039;args&#039;&#039; to send to the method. If &#039;&#039;component&#039;&#039; and &#039;&#039;method&#039;&#039; aren&#039;t provided, it will use the same as in the current page.&lt;br /&gt;
&lt;br /&gt;
====Examples====&lt;br /&gt;
&lt;br /&gt;
=====Group selector=====&lt;br /&gt;
&lt;br /&gt;
Imagine we have an activity that uses groups and we want to let the user select which group he wants to see. A possible solution would be to return all the groups in the same template (hidden), and then show the group user selects. However, we can make it more dynamic and return only the group the user is requesting.&lt;br /&gt;
&lt;br /&gt;
To do so, we&#039;ll use a drop down to select the group. When the user selects a group using this drop down we&#039;ll update the page content to display the new group.&lt;br /&gt;
&lt;br /&gt;
The main difficulty in this is to tell the view which group needs to be selected when the view is loaded. There are 2 ways to do it: using plain HTML or using Angular&#039;s &#039;&#039;ngModel&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
======Using plain HTML======&lt;br /&gt;
&lt;br /&gt;
We need to add a &amp;quot;&#039;&#039;selected&#039;&#039;&amp;quot; attribute to the option that needs to be selected. To do so, we need to pre-caclulate the selected option in the PHP code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $groupid = empty($args-&amp;gt;group) ? 0 : $args-&amp;gt;group; // By default, group 0.&lt;br /&gt;
        $groups = groups_get_activity_allowed_groups($cm, $user-&amp;gt;id);&lt;br /&gt;
        // Detect which group is selected.&lt;br /&gt;
        foreach ($groups as $gid=&amp;gt;$group) {&lt;br /&gt;
            $group-&amp;gt;selected = $gid === $groupid;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $data = array(&lt;br /&gt;
            &#039;cmid&#039; =&amp;gt; $cm-&amp;gt;id,&lt;br /&gt;
            &#039;courseid&#039; =&amp;gt; $args-&amp;gt;courseid,&lt;br /&gt;
            &#039;groups&#039; =&amp;gt; $groups&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
        );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the code above, we&#039;re retrieving the groups the user can see and then we&#039;re adding a &amp;quot;selected&amp;quot; bool to each one to determine which one needs to be selected in the drop down. Finally, we pass the list of groups to the template.&lt;br /&gt;
&lt;br /&gt;
In the template, we display the drop down like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-select (ionChange)=&amp;quot;updateContent({cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;, group: $event})&amp;quot; interface=&amp;quot;popover&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;%#groups%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-option value=&amp;quot;&amp;lt;% id %&amp;gt;&amp;quot; &amp;lt;%#selected%&amp;gt;selected&amp;lt;%/selected%&amp;gt; &amp;gt;&amp;lt;% name %&amp;gt;&amp;lt;/ion-option&amp;gt;&lt;br /&gt;
    &amp;lt;%/groups%&amp;gt;&lt;br /&gt;
&amp;lt;/ion-select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;ionChange&#039;&#039; function will be called everytime the user selects a different group with the drop down. We&#039;re using the function &#039;&#039;updateContent&#039;&#039; to update the current view using the new group. &#039;&#039;$event&#039;&#039; is an Angular variable that will have the selected value (in our case, the group ID that was just selected). This is enough to make the group selector work.&lt;br /&gt;
&lt;br /&gt;
======Using ngModel======&lt;br /&gt;
&lt;br /&gt;
ngModel is an Angular directive that allows storing the value of a certain input/select in a Javascript variable, and also the opposite way: tell the input/select which value to set. The main problem is that we cannot initialize a Javascript variable from the template (Angular doesn&#039;t have &#039;&#039;ng-init&#039;&#039; like in AngularJS), so we&#039;ll use &amp;quot;otherdata&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In the PHP function we&#039;ll return the group that needs to be selected in the &#039;&#039;otherdata&#039;&#039; array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $groupid = empty($args-&amp;gt;group) ? 0 : $args-&amp;gt;group; // By default, group 0.&lt;br /&gt;
        $groups = groups_get_activity_allowed_groups($cm, $user-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
         ...&lt;br /&gt;
&lt;br /&gt;
         return array(&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;otherdata&#039; =&amp;gt; array(&lt;br /&gt;
                &#039;group&#039; =&amp;gt; $groupid&lt;br /&gt;
            ),&lt;br /&gt;
        );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above we don&#039;t need to iterate over the groups array like in the plain HTML example. However, now we&#039;re returning the groupid in the &amp;quot;otherdata&amp;quot; array. As it&#039;s explained in the [[Mobile_support_for_plugins#Using_.E2.80.9Cotherdata.E2.80.9D|Using &amp;quot;otherdata&amp;quot;]] section, this &amp;quot;otherdata&amp;quot; is visible in the templates inside a variable named &#039;&#039;CONTENT_OTHERDATA&#039;&#039;. So in the template we&#039;ll use this variable like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-select [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.group&amp;quot; (ionChange)=&amp;quot;updateContent({cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;, group: CONTENT_OTHERDATA.group})&amp;quot; interface=&amp;quot;popover&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;%#groups%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-option value=&amp;quot;&amp;lt;% id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;% name %&amp;gt;&amp;lt;/ion-option&amp;gt;&lt;br /&gt;
    &amp;lt;%/groups%&amp;gt;&lt;br /&gt;
&amp;lt;/ion-select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Use the rich text editor===&lt;br /&gt;
&lt;br /&gt;
The rich text editor included in the app requires a FormControl to work. You can use the library FormBuilder to create this control (or to create a whole FormGroup if you prefer).&lt;br /&gt;
&lt;br /&gt;
With the following Javascript you&#039;ll be able to create a FormControl:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.control = this.FormBuilder.control(this.CONTENT_OTHERDATA.rte);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above we&#039;re using a value returned in OTHERDATA as the initial value of the rich text editor, but you can use whatever you want.&lt;br /&gt;
&lt;br /&gt;
Then you need to pass this control to the rich text editor in your template:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;ion-item&amp;gt;&lt;br /&gt;
    &amp;lt;core-rich-text-editor item-content [control]=&amp;quot;control&amp;quot; placeholder=&amp;quot;Enter your text here&amp;quot; name=&amp;quot;rte_answer&amp;quot;&amp;gt;&amp;lt;/core-rich-text-editor&amp;gt;&lt;br /&gt;
&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally, there are several ways to send the value in the rich text editor to a WebService to save it. This is one of the simplest options:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;my_webservice&amp;quot; [params]=&amp;quot;{rte: control.value}&amp;quot; ....&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, we&#039;re passing the value of the rich text editor as a parameter to our WebService.&lt;br /&gt;
&lt;br /&gt;
===Initialization===&lt;br /&gt;
&lt;br /&gt;
All handlers can specify a “&#039;&#039;init&#039;&#039;” method in the mobile.php file. This method is meant to return some JavaScript code that needs to be executed as soon as the plugin is retrieved.&lt;br /&gt;
&lt;br /&gt;
When the app retrieves all the handlers, the first thing it will do is call the &#039;&#039;tool_mobile_get_content&#039;&#039; WebService with the init method. This WS call will only receive the default args.&lt;br /&gt;
&lt;br /&gt;
The app will immediately execute the JavaScript code returned by this WS call. This JavaScript can be used to manually register your handlers in the delegates you want, without having to rely on the default handlers built based on the mobile.php data.&lt;br /&gt;
&lt;br /&gt;
The templates returned by this init method will be added to a INIT_TEMPLATES variable that will be passed to all the Javascript code of that handler. This means that the Javascript returned by the init method or the “main” method can access any of the templates HTML like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.INIT_TEMPLATES[‘main’];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In this case, “main” is the ID of the template we want to use.&lt;br /&gt;
&lt;br /&gt;
The same happens with the &#039;&#039;otherdata&#039;&#039; returned by this init method, it is added to a INIT_OTHERDATA variable.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;restrict&#039;&#039; field returned by this init call will be used to determine if your handler is enabled or not. For example, if your handler is for the delegate &#039;&#039;CoreCourseOptionsDelegate&#039;&#039; and you return a list of courseids in restrict-&amp;gt;courses, then your handler will only be enabled in the courses you returned. This only applies to the “default” handlers, if you register your own handler using the Javascript code then you should check yourself if the handler is enabled.&lt;br /&gt;
&lt;br /&gt;
Finally, if you return an object in this init Javascript code, all the properties of that object will be passed to all the Javascript code of that handler so you can use them when the code is run. For example, if your init Javascript code does something like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var result = {&lt;br /&gt;
    MyAddonClass: new MyAddonClass()&lt;br /&gt;
};&lt;br /&gt;
result:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Then, for the rest of Javascript code of your handler (e.g. for the “main” method) you can use this variable like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.MyAddonClass&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Examples====&lt;br /&gt;
&lt;br /&gt;
=====Module link handler=====&lt;br /&gt;
&lt;br /&gt;
A link handler allows you to decide what to do when a link with a certain URL is clicked. This is useful, for example, to open your module when a link to the module is clicked. In this example we’ll create a link handler to detect links to a certificate module using a init JavaScript:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function AddonModCertificateModuleLinkHandler() {&lt;br /&gt;
    that.CoreContentLinksModuleIndexHandler.call(this, that.CoreCourseHelperProvider, &#039;mmaModCertificate&#039;, &#039;certificate&#039;);&lt;br /&gt;
&lt;br /&gt;
    this.name = &amp;quot;AddonModCertificateLinkHandler&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModuleLinkHandler.prototype = Object.create(this.CoreContentLinksModuleIndexHandler.prototype);&lt;br /&gt;
AddonModCertificateModuleLinkHandler.prototype.constructor = AddonModCertificateModuleLinkHandler;&lt;br /&gt;
&lt;br /&gt;
this.CoreContentLinksDelegate.registerHandler(new AddonModCertificateModuleLinkHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Advanced link handler=====&lt;br /&gt;
Link handlers have some advanced features that allow you to change how links behave under different conditions.&lt;br /&gt;
======Patterns======&lt;br /&gt;
You can define a Regular Expression pattern to match certain links.  This will apply the handler only to links that match the pattern.&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function AddonModFooLinkHandler() {&lt;br /&gt;
    ....&lt;br /&gt;
    this.pattern = RegExp(&#039;\/mod\/foo\/specialpage.php&#039;);&lt;br /&gt;
    ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
======Priority======&lt;br /&gt;
Multiple link handlers may apply to a given link.  You can define the order of precedence by setting the priority - the handler with the highest priority will be used.&lt;br /&gt;
All default handlers have a priority of 0, so 1 or higher will override the default.&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function AddonModFooLinkHandler() {&lt;br /&gt;
    ....&lt;br /&gt;
    this.priority = 1;&lt;br /&gt;
    ....&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
======Multiple actions======&lt;br /&gt;
Once a link has been matched, the handler&#039;s getActions() method determines what the link should do.  This method has access to the URL and its parameters.&lt;br /&gt;
Different actions can be returned depending on different conditions.&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
AddonModFooLinkHandler.prototype.getActions = function(siteIds, url, params) {&lt;br /&gt;
    return [{&lt;br /&gt;
        action: function(siteId, navCtrl) {&lt;br /&gt;
            // The actual behaviour of the link goes here.&lt;br /&gt;
        },&lt;br /&gt;
        sites: [...]&lt;br /&gt;
    }, {&lt;br /&gt;
        ...&lt;br /&gt;
    }];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Once handlers have been matched for a link, the actions will be fetched for all the matching handlers, in priorty order.  The first &amp;quot;valid&amp;quot; action will be used to open the link.&lt;br /&gt;
If your handler is matched with a link, but a condition assessed in the getActions() function means you want to revert to the next highest priorty handler, you can &amp;quot;invalidate&amp;quot;&lt;br /&gt;
your action by settings its sites propety to an empty array.&lt;br /&gt;
======Complex example======&lt;br /&gt;
This will match all URLs containing /mod/foo/, and force those with an id parameter that&#039;s not in the &amp;quot;supportedModFoos&amp;quot; array to open in the user&#039;s browser, rather than the app.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
var supportedModFoos = [...];&lt;br /&gt;
function AddonModFooLinkHandler() {&lt;br /&gt;
    this.pattern = new RegExp(&#039;\/mod\/foo\/&#039;);&lt;br /&gt;
    this.name = &amp;quot;AddonModFooLinkHandler&amp;quot;;&lt;br /&gt;
    this.priority = 1;&lt;br /&gt;
}&lt;br /&gt;
AddonModFooLinkHandler.prototype = Object.create(that.CoreContentLinksHandlerBase.prototype);&lt;br /&gt;
AddonModFooLinkHandler.prototype.constructor = AddonModFooLinkHandler;&lt;br /&gt;
AddonModFooLinkHandler.prototype.getActions = function(siteIds, url, params) {     &lt;br /&gt;
    var action = {&lt;br /&gt;
        action: function() {&lt;br /&gt;
            that.CoreUtilsProvider.openInBrowser(url);&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
    if (supportedModFoos.indexOf(parseInt(params.id)) !== -1) {&lt;br /&gt;
        action.sites = [];&lt;br /&gt;
    }&lt;br /&gt;
    return [action];&lt;br /&gt;
};&lt;br /&gt;
that.CoreContentLinksDelegate.registerHandler(new AddonModFooLinkHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Module prefetch handler=====&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;CoreCourseModuleDelegate&#039;&#039; handler allows you to define a list of &#039;&#039;offlinefunctions&#039;&#039; to prefetch a module. However, you might want to create your own prefetch handler to determine what needs to be downloaded. For example, you might need to chain WS calls (pass the result of a WS call to the next one), and this cannot be done using &#039;&#039;offlinefunctions&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Here’s an example on how to create a prefetch handler using init JS:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
// Create a class that &amp;quot;inherits&amp;quot; from CoreCourseActivityPrefetchHandlerBase.&lt;br /&gt;
function AddonModCertificateModulePrefetchHandler() {&lt;br /&gt;
    that.CoreCourseActivityPrefetchHandlerBase.call(this, that.TranslateService, that.CoreAppProvider, that.CoreUtilsProvider,&lt;br /&gt;
            that.CoreCourseProvider, that.CoreFilepoolProvider, that.CoreSitesProvider, that.CoreDomUtilsProvider);&lt;br /&gt;
&lt;br /&gt;
    this.name = &amp;quot;AddonModCertificateModulePrefetchHandler&amp;quot;;&lt;br /&gt;
    this.modName = &amp;quot;certificate&amp;quot;;&lt;br /&gt;
    this.component = &amp;quot;mod_certificate&amp;quot;; // This must match the plugin identifier from db/mobile.php, otherwise the download link in the context menu will not update correctly.&lt;br /&gt;
    this.updatesNames = /^configuration$|^.*files$/;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype = Object.create(this.CoreCourseActivityPrefetchHandlerBase.prototype);&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype.constructor = AddonModCertificateModulePrefetchHandler;&lt;br /&gt;
&lt;br /&gt;
// Override the prefetch call.&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype.prefetch = function(module, courseId, single, dirPath) {&lt;br /&gt;
    return this.prefetchPackage(module, courseId, single, prefetchCertificate);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function prefetchCertificate(module, courseId, single, siteId) {&lt;br /&gt;
    // Perform all the WS calls.&lt;br /&gt;
    // You can access most of the app providers using that.ClassName. E.g. that.CoreWSProvider.call().&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
this.CoreCourseModulePrefetchDelegate.registerHandler(new AddonModCertificateModulePrefetchHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One relatively simple full example is where you have a function that needs to work offline, but it has an additional argument other than the standard ones. You can imagine for this an activity like the book module, where it has multiple pages for the same cmid. The app will not automatically work with this situation - it will call the offline function with the standard arguments only, so you won&#039;t be able to prefetch all the possible parameters. &lt;br /&gt;
&lt;br /&gt;
To deal with this, you need to implement a web service in your Moodle component that returns the list of possible extra arguments, and then you can call this web service and loop around doing the same thing the app does when it prefetches the offline functions. Here is an example from a third-party module (showing only the actual prefetch function - the rest of the code is as above) where there are multiple values of a custom &#039;section&#039; parameter for the mobile function &#039;mobile_document_view&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
function prefetchOucontent(module, courseId, single, siteId) {&lt;br /&gt;
    var component = &#039;mod_oucontent&#039;;&lt;br /&gt;
&lt;br /&gt;
    // Get the site, first.&lt;br /&gt;
    return that.CoreSitesProvider.getSite(siteId).then(function(site) {&lt;br /&gt;
        // Read the list of pages in this document using a web service.&lt;br /&gt;
        return site.read(&#039;mod_oucontent_get_page_list&#039;, {&#039;cmid&#039;: module.id}).then(function(response) {&lt;br /&gt;
            var promises = [];&lt;br /&gt;
&lt;br /&gt;
            // For each page, read and process the page - this is a copy of logic in the app at&lt;br /&gt;
            // siteplugins.ts (prefetchFunctions), but modified to add the custom argument.&lt;br /&gt;
            for(var i = 0; i &amp;lt; response.length; i++) {&lt;br /&gt;
                var args = {&lt;br /&gt;
                    courseid: courseId,&lt;br /&gt;
                    cmid: module.id,&lt;br /&gt;
                    userid: site.getUserId()&lt;br /&gt;
                };&lt;br /&gt;
                if (response[i] !== &#039;&#039;) {&lt;br /&gt;
                    args.section = response[i];&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                promises.push(that.CoreSitePluginsProvider.getContent(&lt;br /&gt;
                        component, &#039;mobile_document_view&#039;, args).then(&lt;br /&gt;
                        function(result) {&lt;br /&gt;
                            var subPromises = [];&lt;br /&gt;
                            if (result.files &amp;amp;&amp;amp; result.files.length) {&lt;br /&gt;
                                subPromises.push(that.CoreFilepoolProvider.downloadOrPrefetchFiles(&lt;br /&gt;
                                        site.id, result.files, true, false, component, module.id));&lt;br /&gt;
                            }&lt;br /&gt;
                            return Promise.all(subPromises);&lt;br /&gt;
                        }));&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            return Promise.all(promises);&lt;br /&gt;
        });&lt;br /&gt;
    });&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Single activity course format=====&lt;br /&gt;
&lt;br /&gt;
In the following example, the value of INIT_TEMPLATES[&amp;quot;main&amp;quot;] is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;core-dynamic-component [component]=&amp;quot;componentClass&amp;quot; [data]=&amp;quot;data&amp;quot;&amp;gt;&amp;lt;/core-dynamic-component&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This template is returned by the init method. And this is the JavaScript code returned by the init method:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function getAddonSingleActivityFormatComponent() {&lt;br /&gt;
    function AddonSingleActivityFormatComponent() {&lt;br /&gt;
        this.data = {};&lt;br /&gt;
    };&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.constructor = AddonSingleActivityFormatComponent;&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.ngOnChanges = function(changes) {&lt;br /&gt;
        var self = this;&lt;br /&gt;
&lt;br /&gt;
        if (this.course &amp;amp;&amp;amp; this.sections &amp;amp;&amp;amp; this.sections.length) {&lt;br /&gt;
            var module = this.sections[0] &amp;amp;&amp;amp; this.sections[0].modules &amp;amp;&amp;amp; this.sections[0].modules[0];&lt;br /&gt;
            if (module &amp;amp;&amp;amp; !this.componentClass) {&lt;br /&gt;
                that.CoreCourseModuleDelegate.getMainComponent(that.Injector, this.course, module).then((component) =&amp;gt; {&lt;br /&gt;
                    self.componentClass = component || that.CoreCourseUnsupportedModuleComponent;&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            this.data.courseId = this.course.id;&lt;br /&gt;
            this.data.module = module;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.doRefresh = function(refresher, done) {&lt;br /&gt;
        return Promise.resolve(this.dynamicComponent.callComponentFunction(&amp;quot;doRefresh&amp;quot;, [refresher, done]));&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
return AddonSingleActivityFormatComponent;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function AddonSingleActivityFormatHandler() {&lt;br /&gt;
    this.name = &amp;quot;singleactivity&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.constructor = AddonSingleActivityFormatHandler;&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.isEnabled = function() {&lt;br /&gt;
    return true;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.canViewAllSections = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.getCourseTitle = function(course, sections) {&lt;br /&gt;
    if (sections &amp;amp;&amp;amp; sections[0] &amp;amp;&amp;amp; sections[0].modules &amp;amp;&amp;amp; sections[0].modules[0]) {&lt;br /&gt;
        return sections[0].modules[0].name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return course.fullname || &amp;quot;&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.displayEnableDownload = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.displaySectionSelector = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.getCourseFormatComponent = function(injector, course) {&lt;br /&gt;
    that.Injector = injector || that.Injector;&lt;br /&gt;
&lt;br /&gt;
    return that.CoreCompileProvider.instantiateDynamicComponent(that.INIT_TEMPLATES[&amp;quot;main&amp;quot;], getAddonSingleActivityFormatComponent(), injector);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
this.CoreCourseFormatDelegate.registerHandler(new AddonSingleActivityFormatHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the JavaScript API===&lt;br /&gt;
&lt;br /&gt;
The Javascript API is partly supported right now, only the delegates specified in the section [[Mobile_support_for_plugins#Templates_downloaded_on_login_and_rendered_using_JS_data_2|Templates downloaded on login and rendered using JS data]] supports it now. This API allows you to override any of the functions of the default handler. &lt;br /&gt;
&lt;br /&gt;
The “method” specified in a handler registered in the &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; will be called immediately after the init method, and the Javascript returned by this method will be run. If this Javascript code returns an object with certain functions, these function will override the ones in the default handler.&lt;br /&gt;
&lt;br /&gt;
For example, if the Javascript returned by the method returns something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var result = {&lt;br /&gt;
    getData: function(field, signup, registerAuth, formValues) {&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
result;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The the &#039;&#039;getData&#039;&#039; function of the default handler will be overridden by the returned getData function.&lt;br /&gt;
&lt;br /&gt;
The default handler for &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; only has 2 functions: &#039;&#039;getComponent&#039;&#039; and &#039;&#039;getData&#039;&#039;. In addition, the JavaScript code can return an extra function named &#039;&#039;componentInit&#039;&#039; that will be executed when the component returned by &#039;&#039;getComponent&#039;&#039; is initialized.&lt;br /&gt;
&lt;br /&gt;
Here’s an example on how to support the text user profile field using this API:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
var result = {&lt;br /&gt;
    componentInit: function() {&lt;br /&gt;
        if (this.field &amp;amp;&amp;amp; this.edit &amp;amp;&amp;amp; this.form) {&lt;br /&gt;
            this.field.modelName = &amp;quot;profile_field_&amp;quot; + this.field.shortname;&lt;br /&gt;
&lt;br /&gt;
            if (this.field.param2) {&lt;br /&gt;
                this.field.maxlength = parseInt(this.field.param2, 10) || &amp;quot;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            this.field.inputType = that.CoreUtilsProvider.isTrueOrOne(this.field.param3) ? &amp;quot;password&amp;quot; : &amp;quot;text&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            var formData = {&lt;br /&gt;
                value: this.field.defaultdata,&lt;br /&gt;
                disabled: this.disabled&lt;br /&gt;
            };&lt;br /&gt;
&lt;br /&gt;
            this.form.addControl(this.field.modelName, that.FormBuilder.control(formData, this.field.required &amp;amp;&amp;amp; !this.field.locked ? that.Validators.required : null));&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    getData: function(field, signup, registerAuth, formValues) {&lt;br /&gt;
        var name = &amp;quot;profile_field_&amp;quot; + field.shortname;&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            type: &amp;quot;text&amp;quot;,&lt;br /&gt;
            name: name,&lt;br /&gt;
            value: that.CoreTextUtilsProvider.cleanTags(formValues[name])&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
result;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Translate dynamic strings===&lt;br /&gt;
&lt;br /&gt;
If you wish to have an element that displays a localised string based on value from your template you can doing something like:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;ion-card&amp;gt;&lt;br /&gt;
    &amp;lt;ion-card-content translate&amp;gt;&lt;br /&gt;
        plugin.mod_myactivity.&amp;lt;% status %&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-card-content&amp;gt;&lt;br /&gt;
&amp;lt;/ion-card&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This could save you from having to write something like when only one value should be displayed:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
&amp;lt;ion-card&amp;gt;&lt;br /&gt;
    &amp;lt;ion-card-content&amp;gt;&lt;br /&gt;
        &amp;lt;%#isedting%&amp;gt;{{ &#039;plugin.mod_myactivity.editing&#039; | translate }}&amp;lt;%/isediting%&amp;gt;&lt;br /&gt;
        &amp;lt;%#isopen%&amp;gt;{{ &#039;plugin.mod_myactivity.open&#039; | translate }}&amp;lt;%/isopen%&amp;gt;&lt;br /&gt;
        &amp;lt;%#isclosed%&amp;gt;{{ &#039;plugin.mod_myactivity.closed&#039; | translate }}&amp;lt;%/isclosed%&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-card-content&amp;gt;&lt;br /&gt;
&amp;lt;/ion-card&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using strings with dates===&lt;br /&gt;
&lt;br /&gt;
If you have a string that you wish to pass a formatted date for example in the Moodle language file you have:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;strwithdate&#039;] = &#039;This string includes a date of {$a-&amp;gt;date} in the middle of it.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can localise the string correctly in your template using something like the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
{{ &#039;plugin.mod_myactivity.strwithdate&#039; | translate: {$a: { date: &amp;lt;% timestamp %&amp;gt; * 1000 | coreFormatDate: &amp;quot;dffulldate&amp;quot; } } }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A Unix timestamp must be multiplied by 1000 as the Mobile App expects millisecond timestamps, where as Unix timestamps are in seconds.&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
=== Invalid response received ===&lt;br /&gt;
&lt;br /&gt;
You might receive this error when using the &amp;quot;core-site-plugins-call-ws&amp;quot; directive or similar. By default, the app expects all WebService calls to return an object, if your WebService returns another type (string, bool, ...) then you need to specify it using the preSets attribute of the directive. For example, if your WS returns a boolean value, then you should specify it like this:&lt;br /&gt;
&lt;br /&gt;
[preSets]=&amp;quot;{typeExpected: &#039;boolean&#039;}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In a similar way, if your WebService returns null you need to tell the app not to expect any result using the preSets:&lt;br /&gt;
&lt;br /&gt;
[preSets]=&amp;quot;{responseExpected: false}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS ===&lt;br /&gt;
&lt;br /&gt;
Some directives allow you to specify a form id or name to send the data from the form to a certain WS. These directives look for HTML inputs to retrieve the data to send. However, ion-radio, ion-checkbox and ion-select don&#039;t use HTML inputs, they simulate them, so the directive isn&#039;t going to find their data and so it won&#039;t be sent to the WebService.&lt;br /&gt;
&lt;br /&gt;
There are 2 workarounds to fix this problem. It seems that the next major release of Ionic framework does use HTML inputs, so these are temporary solutions.&lt;br /&gt;
&lt;br /&gt;
==== Sending the data manually ====&lt;br /&gt;
&lt;br /&gt;
The first solution is to send the missing params manually using the &amp;quot;&#039;&#039;params&#039;&#039;&amp;quot; property. We will use &#039;&#039;ngModel&#039;&#039; to store the input value in a variable, and this variable will be passed to the params. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too.&lt;br /&gt;
&lt;br /&gt;
For example, if you have a template like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;ion-list radio-group name=&amp;quot;responses&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;myws&amp;quot; [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;}&amp;quot; form=&amp;quot;myform&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mycomponent.save&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you should modify it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;ion-list radio-group [(ngModel)]=&amp;quot;responses&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;myws&amp;quot; [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;, responses: responses}&amp;quot; form=&amp;quot;myform&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mycomponent.save&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basically, you need to add &#039;&#039;ngModel&#039;&#039; to the affected element (in this case, the &#039;&#039;radio-group&#039;&#039;). You can put whatever name you want as the value, we used &amp;quot;responses&amp;quot;. With this, everytime the user selects a radio button the value will be stored in a variable named &amp;quot;responses&amp;quot;. Then, in the button we are passing this variable to the params of the WebService.&lt;br /&gt;
&lt;br /&gt;
Please notice that the &amp;quot;form&amp;quot; attribute has priority over &amp;quot;params&amp;quot;, so if you have an input with name=&amp;quot;responses&amp;quot; it will override what you&#039;re manually passing to params.&lt;br /&gt;
&lt;br /&gt;
==== Using a hidden input ====&lt;br /&gt;
&lt;br /&gt;
Since the directive is looking for HTML inputs, you need to add one with the value to send to the server. You can use &#039;&#039;ngModel&#039;&#039; to synchronize your ion-radio/ion-checkbox/ion-select with the new hidden input. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too.&lt;br /&gt;
&lt;br /&gt;
For example, if you have a radio button like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you should modify it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot; [(ngModel)]=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;ion-input type=&amp;quot;hidden&amp;quot; [ngModel]=&amp;quot;responses&amp;quot; name=&amp;quot;responses&amp;quot;&amp;gt;&amp;lt;/ion-input&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we&#039;re using a variable named &amp;quot;responses&amp;quot; to synchronize the data between the &#039;&#039;radio-group&#039;&#039; and the hidden input. You can use whatever name you want.&lt;br /&gt;
&lt;br /&gt;
=== I can&#039;t return an object or array in otherdata ===&lt;br /&gt;
&lt;br /&gt;
If you try to return an object or an array in any field inside &#039;&#039;otherdata&#039;&#039;, the WebService call will fail with the following error:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Scalar type expected, array or object received&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Each field in &#039;&#039;otherdata&#039;&#039; must be a string, number or boolean, it cannot be an object or array. To make it work, you need to encode your object or array into a JSON string:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; json_encode($data))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The app will automatically parse this JSON and convert it back into an array or object.&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===Accepting dynamic names in a WebService===&lt;br /&gt;
&lt;br /&gt;
We want to display a form where the names of the fields are dynamic, like it happens in quiz. This data will be sent to a new WebService that we have created.&lt;br /&gt;
&lt;br /&gt;
The first issue we find is that the WebService needs to define the names of the parameters received, but in this case they&#039;re dynamic. The solution is to accept an array of objects with name and value. So in the &#039;&#039;_parameters()&#039;&#039; function of our new WebService, we will add this parameter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;data&#039; =&amp;gt; new external_multiple_structure(&lt;br /&gt;
     new external_single_structure(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; new external_value(PARAM_RAW, &#039;data name&#039;),&lt;br /&gt;
            &#039;value&#039; =&amp;gt; new external_value(PARAM_RAW, &#039;data value&#039;),&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;The data to be saved&#039;, VALUE_DEFAULT, array()&lt;br /&gt;
)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to adapt our form to send the data as the WebService requires it. In our template, we have a button with the directive &#039;&#039;core-site-plugins-call-ws&#039;&#039; that will send the form data to our WebService. To make this work we will have to pass the parameters manually, without using the &amp;quot;&#039;&#039;form&#039;&#039;&amp;quot; attribute, because we need to format the data before it is sent.&lt;br /&gt;
&lt;br /&gt;
Since we will send the params manually and we want it all to be sent in the same array, we will use &#039;&#039;ngModel&#039;&#039; to store the input data into a variable that we&#039;ll call &amp;quot;data&amp;quot;, but you can use the name you want. This &amp;quot;data&amp;quot; will be an object that will hold the input data with the format &amp;quot;name-&amp;gt;value&amp;quot;. For example, if I have an input with name &amp;quot;a1&amp;quot; and value &amp;quot;My answer&amp;quot;, the data object will be:&lt;br /&gt;
&lt;br /&gt;
{a1: &amp;quot;My answer&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
So we need to add &#039;&#039;ngModel&#039;&#039; to all the inputs whose values need to be sent to the &amp;quot;data&amp;quot; WS param. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&amp;lt;ion-input name=&amp;quot;&amp;lt;% name %&amp;gt;&amp;quot; [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.data[&#039;&amp;lt;% name %&amp;gt;&#039;]&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, we&#039;re using &#039;&#039;CONTENT_OTHERDATA&#039;&#039; to store the data. We do it like this because we&#039;ll use &#039;&#039;otherdata&#039;&#039; to initialize the form, setting the values the user has already stored. If you don&#039;t need to initialize the form, then you can use the variable &amp;quot;dataObject&amp;quot;, an empty object that the Mobile app creates for you: [(ngModel)]=&amp;quot;dataObject[&#039;&amp;lt;% name %&amp;gt;&#039;]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The Mobile app has a function that allows you to convert this data object into an array like the one the WS expects: &#039;&#039;objectToArrayOfObjects&#039;&#039;. So in our button we&#039;ll use this function to format the data before it&#039;s sent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;my_ws_name&amp;quot;&lt;br /&gt;
    [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;, data: CoreUtilsProvider.objectToArrayOfObjects(CONTENT_OTHERDATA.data, &#039;name&#039;, &#039;value&#039;)}&amp;quot;&lt;br /&gt;
    successMessage&lt;br /&gt;
    refreshOnSuccess=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see in the example above, we&#039;re specifying that the keys of the &amp;quot;data&amp;quot; object need to be stored in a property named &amp;quot;name&amp;quot;, and the values need to be stored in a property named &amp;quot;value&amp;quot;. If your WebService expects different names you need to change the parameters of the function &#039;&#039;objectToArrayOfObjects&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If you open your plugin now in the Mobile app it will display an error in the Javascript console. The reason is that the variable &amp;quot;data&amp;quot; doesn&#039;t exist inside &#039;&#039;CONTENT_OTHERDATA&#039;&#039;. As it is explained in previous sections, &#039;&#039;CONTENT_OTHERDATA&#039;&#039; holds the data that you return in &#039;&#039;otherdata&#039;&#039; for your method. We&#039;ll use &#039;&#039;otherdata&#039;&#039; to initialize the values to be displayed in the form.&lt;br /&gt;
&lt;br /&gt;
If the user hasn&#039;t answered the form yet, we can initialize the &amp;quot;data&amp;quot; object as an empty object. Please remember that we cannot return arrays or objects in &#039;&#039;otherdata&#039;&#039;, so we&#039;ll return a JSON string.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; &#039;{}&#039;)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the code above, the form will always be empty when the user opens it. But now we want to check if the user has already answered the form and fill the form with the previous values. We will do it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$userdata = get_user_responses(); // It will held the data in a format name-&amp;gt;value. Example: array(&#039;a1&#039; =&amp;gt; &#039;My value&#039;).&lt;br /&gt;
...&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; json_encode($userdata))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now the user will be able to see previous values when the form is opened, and clicking the button will send the data to our WebService in array format.&lt;br /&gt;
&lt;br /&gt;
==Moodle plugins with mobile support==&lt;br /&gt;
&lt;br /&gt;
* Group choice: [https://moodle.org/plugins/mod_choicegroup Moodle plugins directory entry] and [https://github.com/ndunand/moodle-mod_choicegroup code in github].&lt;br /&gt;
* Custom certificate: [https://moodle.org/plugins/mod_customcert Moodle plugins directory entry] and [https://github.com/markn86/moodle-mod_customcert code in github].&lt;br /&gt;
* Gapfill question type: [https://moodle.org/plugins/qtype_gapfill Moodle plugins directory entry] and [https://github.com/marcusgreen/moodle-qtype_gapfill in github].&lt;br /&gt;
* Wordselect question type: [https://moodle.org/plugins/qtype_wordselect Moodle plugins directory entry] and [https://github.com/marcusgreen/moodle-qtype_wordselect in github].&lt;br /&gt;
* RegExp question type: [https://moodle.org/plugins/qtype_regexp Moodle plugins directory entry] and [https://github.com/rezeau/moodle-qtype_regexp in github].&lt;br /&gt;
* Certificate: [https://moodle.org/plugins/mod_certificate Moodle plugins directory entry] and [https://github.com/markn86/moodle-mod_certificate in github].&lt;br /&gt;
* Attendance [https://moodle.org/plugins/mod_attendance Moodle plugins directory entry] and [https://github.com/danmarsden/moodle-mod_attendance in github].&lt;br /&gt;
&lt;br /&gt;
See the complete list in the plugins database [https://moodle.org/plugins/browse.php?list=award&amp;amp;id=6 here] (it may contain some outdated plugins)&lt;br /&gt;
[[Category:Mobile]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=customscripts&amp;diff=55696</id>
		<title>customscripts</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=customscripts&amp;diff=55696"/>
		<updated>2019-03-13T09:56:05Z</updated>

		<summary type="html">&lt;p&gt;Fox: Typos and updating links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Custom Scripts Mechanism==&lt;br /&gt;
&lt;br /&gt;
 Any scripts that are called directly via a url (eg index.php, user/view.php) can now be customised&lt;br /&gt;
 by placing a file with the same name (including directories) in my_moodle_data_dir/customscripts&lt;br /&gt;
 For example:&lt;br /&gt;
 my_moodle_data_dir/customscripts/index.php; my_moodle_data_dir/customscripts/user/view.php&lt;br /&gt;
&lt;br /&gt;
* this is for people making short term changes to VISIBLE web pages in the moodle source code&lt;br /&gt;
** need to check relative links ; for example: never require ../config.php&lt;br /&gt;
** cannot add new files to customscripts folder because they are not accessible directly via web.&lt;br /&gt;
** better to use cvs or cogito for long term management of customisations to Moodle code&lt;br /&gt;
&lt;br /&gt;
* it seems to have been used extensively only by the [[Moodle 2 for mobile|Moodle for Mobiles]] project&lt;br /&gt;
&lt;br /&gt;
* to enable Custom Scripts, add $CFG-&amp;gt;customscripts=path/to/customscript/folder (see [[:en:Configuration_file|Configuration file]])&lt;br /&gt;
&lt;br /&gt;
==Things to keep in mind when using customscripts==&lt;br /&gt;
&lt;br /&gt;
* customscripts hook the derivated script from the near end of the setup.php script. This means that the config.php file has already been included by the caller and should&lt;br /&gt;
not be called again.&lt;br /&gt;
* You cannot override an internal script (MOODLE_INTERNAL) of Moodle, you can only customscript an &#039;entry&#039; page. If the change you need is deeper in an internal library, you need to override the entry page, and probably all the required path from the entry point down to the function you want to change the behaviour.&lt;br /&gt;
* The original script might have pre-required some libraries, or defined some early function or defines that are active before the hooks is invoked, such definitions should not be required or defined again in the customscript. &lt;br /&gt;
* When a customscript returns, it gives control back to the setup.php script that will continue executing the original php page.Thus if a customscript replaces the original script, it should end with an exit statement.&lt;br /&gt;
&lt;br /&gt;
==Caveat of customscripting==&lt;br /&gt;
&lt;br /&gt;
Customscripting is efficient to locally hack a behaviour that is not easy to override using class factories provided by the core architecture or renderer overloading, but your site will run using a&lt;br /&gt;
copy of the core code that WILL NOT integrate the code updates when you upgrade Moodle to a higher version. So customscripting might be your last choice to get a feature change in Moodle after all&lt;br /&gt;
other techniques have been examinated : &lt;br /&gt;
&lt;br /&gt;
* relocate the feature in a plugin&lt;br /&gt;
* override core code with proposed factories and overloading mechanisms&lt;br /&gt;
* finding a way to get the feature in another way (using other plugins, other method)&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* http://moodle.org/mod/forum/discuss.php?d=31895&lt;br /&gt;
* https://tracker.moodle.org/issues/?jql=text%20~%20%22customscripts%22&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_classic&amp;diff=55652</id>
		<title>Creating a theme based on classic</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_classic&amp;diff=55652"/>
		<updated>2019-03-06T08:15:39Z</updated>

		<summary type="html">&lt;p&gt;Fox: Docs for Moodle 3.7 and small improvments&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.7}}&lt;br /&gt;
{{Template:Themes}}&lt;br /&gt;
&lt;br /&gt;
This is a tutorial for how to create a new theme based on the Classic theme.&lt;br /&gt;
&lt;br /&gt;
Moodle 3.7 includes a new core theme named &amp;quot;Classic&amp;quot; which is a starting point for themers wanting to build Moodle theme using a 3 column layout without the Boost navdrawer and settings menus.&lt;br /&gt;
&lt;br /&gt;
== Getting started ==&lt;br /&gt;
What is a theme? A theme in Moodle is just another type of plugin that can be developed. Themes are responsible for setting up the structure of each page and have the ability to customise the output of any page in Moodle.&lt;br /&gt;
&lt;br /&gt;
This tutorial is based on the tutorial https://docs.moodle.org/dev/Creating_a_theme_based_on_boost. You can download it or view the source code for it here: https://github.com/bmbrands/moodle-theme_picture&lt;br /&gt;
&lt;br /&gt;
=== Choosing a name ===&lt;br /&gt;
Your new theme will need a name. Try and think of something short and memorable - and make sure it is not a name that has already been used by someone else. A quick search on the [https://moodle.org/plugins moodle.org/plugins] can save you a lot of work renaming things later.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s call our new example theme &amp;quot;picture&amp;quot; as we will add some settings to allow &amp;quot;pictures&amp;quot; in various places in Moodle.&lt;br /&gt;
&lt;br /&gt;
=== Starting files ===&lt;br /&gt;
As a plugin, themes must start with the basic structure of a plugin in Moodle. See https://docs.moodle.org/dev/Tutorial#The_skeleton_of_your_plugin for an overview of the files common to all plugins in Moodle.&lt;br /&gt;
&lt;br /&gt;
Following this guide you can start creating your own theme. First, we create the folder for the new theme under under &amp;quot;/theme/&amp;quot; folder in the Moodle root directory.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/theme/picture/&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to add some standard plugin files to our theme. First is version.php&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/theme/picture/version.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// Every file should have GPL and copyright in the header - we skip it in tutorials but you should not skip it for real.&lt;br /&gt;
&lt;br /&gt;
// This line protects the file from being accessed by a URL directly.&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
// This is the version of the plugin.&lt;br /&gt;
$plugin-&amp;gt;version = 2019030400;&lt;br /&gt;
&lt;br /&gt;
// This is the version of Moodle this plugin requires.&lt;br /&gt;
$plugin-&amp;gt;requires = 2018051700;&lt;br /&gt;
&lt;br /&gt;
// This is the component name of the plugin - it always starts with &#039;theme_&#039;&lt;br /&gt;
// for themes and should be the same as the name of the folder.&lt;br /&gt;
$plugin-&amp;gt;component = &#039;theme_picture&#039;;&lt;br /&gt;
&lt;br /&gt;
// This is a list of plugins, this plugin depends on (and their versions).&lt;br /&gt;
$plugin-&amp;gt;dependencies = [&lt;br /&gt;
    &#039;theme_classic&#039; =&amp;gt; 2018120700&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
// This is a stable release.&lt;br /&gt;
$plugin-&amp;gt;maturity = MATURITY_STABLE;&lt;br /&gt;
&lt;br /&gt;
// This is the named version.&lt;br /&gt;
$plugin-&amp;gt;release = 1.0;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need a language file so that all our strings can be translated into different languages. The name of this file is the component name of our plugin and it sits in the lang/en/ folder for our plugin. We can include translations of our plugin, but we can also provide translations via the https://lang.moodle.org/ website once our plugin has been published to the plugins database at http://www.moodle.org/plugins/.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;/theme/picture/lang/en/theme_picture.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// Every file should have GPL and copyright in the header - we skip it in tutorials but you should not skip it for real.&lt;br /&gt;
&lt;br /&gt;
// This line protects the file from being accessed by a URL directly.&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
// A description shown in the admin theme selector.&lt;br /&gt;
$string[&#039;choosereadme&#039;] = &#039;Theme picture is a child theme of the Classic. It adds the ability to upload background photos.&#039;;&lt;br /&gt;
// The name of our plugin.&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Picture&#039;;&lt;br /&gt;
// We need to include a lang string for each block region.&lt;br /&gt;
$string[&#039;region-side-pre&#039;] = &#039;Left&#039;;&lt;br /&gt;
$string[&#039;region-side-post&#039;] = &#039;Right&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Theme specific files ===&lt;br /&gt;
Theme plugins have a few more standard files they need to define.&lt;br /&gt;
&lt;br /&gt;
Themes require a favicon file to show in the address bar. See [[http://docs.moodle.org/en/Favicon Favicon]].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pix/favicon.ico&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(Image file not shown).&lt;br /&gt;
&lt;br /&gt;
Themes also require an example screenshot to be displayed in the theme selector.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;pix/screenshot.jpg&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
(Image file not shown).&lt;br /&gt;
&lt;br /&gt;
Themes require a lib.php file. This file contains callbacks used by various API&#039;s in Moodle. Initially this file can be empty, but as we add features to our theme we will need to add some functions here.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// Every file should have GPL and copyright in the header - we skip it in tutorials but you should not skip it for real.&lt;br /&gt;
&lt;br /&gt;
// This line protects the file from being accessed by a URL directly.&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
// We will add callbacks here as we add features to our theme.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Theme config goes in a config.php file. This is one of the most important files in our theme. Once we add this file we will be ready to test our theme for the first time.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Picture config.&lt;br /&gt;
 *&lt;br /&gt;
 * @package   theme_picture&lt;br /&gt;
 * @copyright 2016 Damyon Wiese&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
// This line protects the file from being accessed by a URL directly.&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
// $THEME is defined before this page is included and we can define settings by adding properties to this global object.&lt;br /&gt;
&lt;br /&gt;
// The first setting we need is the name of the theme. This should be the last part of the component name, and the same&lt;br /&gt;
// as the directory name for our theme.&lt;br /&gt;
$THEME-&amp;gt;name = &#039;picture&#039;;&lt;br /&gt;
&lt;br /&gt;
// This setting list the style sheets we want to include in our theme. Because we want to use SCSS instead of CSS - we won&#039;t&lt;br /&gt;
// list any style sheets. If we did we would list the name of a file in the /styles/ folder for our theme without any css file&lt;br /&gt;
// extensions.&lt;br /&gt;
$THEME-&amp;gt;sheets = [];&lt;br /&gt;
&lt;br /&gt;
// This is a setting that can be used to provide some styling to the content in the TinyMCE text editor. This is no longer the&lt;br /&gt;
// default text editor and &amp;quot;Atto&amp;quot; does not need this setting so we won&#039;t provide anything. If we did it would work the same&lt;br /&gt;
// as the previous setting - listing a file in the /styles/ folder.&lt;br /&gt;
$THEME-&amp;gt;editor_sheets = [];&lt;br /&gt;
&lt;br /&gt;
// This is a critical setting. We want to inherit from theme_classic because it provides a great starting point for SCSS bootstrap4&lt;br /&gt;
// themes. We have added add more than one parent here to inherit from multiple parents, and if we did they would be processed in&lt;br /&gt;
// order of importance (later themes overriding earlier ones). Things we will inherit from the parent theme include&lt;br /&gt;
// styles and mustache templates and some (not all) settings.&lt;br /&gt;
$THEME-&amp;gt;parents = [&#039;boost&#039;, &#039;classic&#039;];&lt;br /&gt;
&lt;br /&gt;
// A dock is a way to take blocks out of the page and put them in a persistent floating area on the side of the page.&lt;br /&gt;
// does not support a dock so we won&#039;t either - but look at bootstrapbase for an example of a theme with a dock.&lt;br /&gt;
$THEME-&amp;gt;enable_dock = false;&lt;br /&gt;
&lt;br /&gt;
// This is an old setting used to load specific CSS for some YUI JS. We don&#039;t need it in Classic based themes because Classic&lt;br /&gt;
// provides default styling for the YUI modules that we use. It is not recommended to use this setting anymore.&lt;br /&gt;
$THEME-&amp;gt;yuicssmodules = array();&lt;br /&gt;
&lt;br /&gt;
// Most themes will use this rendererfactory as this is the one that allows the theme to override any other renderer.&lt;br /&gt;
$THEME-&amp;gt;rendererfactory = &#039;theme_overridden_renderer_factory&#039;;&lt;br /&gt;
&lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_picture_get_pre_scss&#039;;&lt;br /&gt;
&lt;br /&gt;
// Since we are using 2 parent themes the correct location of the layout files needs to be defined. For this theme we need the multiple&lt;br /&gt;
// column layouts.&lt;br /&gt;
$THEME-&amp;gt;layouts = [&lt;br /&gt;
    // Most backwards compatible layout without the blocks - this is the layout used by default.&lt;br /&gt;
    &#039;base&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
    ),&lt;br /&gt;
    // Standard layout with blocks, this is recommended for most pages with general information.&lt;br /&gt;
    &#039;standard&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;, &#039;side-post&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // Main course page.&lt;br /&gt;
    &#039;course&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;, &#039;side-post&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;langmenu&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;coursecategory&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // Part of course, typical for modules - default page layout if $cm specified in require_login().&lt;br /&gt;
    &#039;incourse&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // The site home page.&lt;br /&gt;
    &#039;frontpage&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;, &#039;side-post&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofullheader&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // Server administration scripts.&lt;br /&gt;
    &#039;admin&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // My dashboard page.&lt;br /&gt;
    &#039;mydashboard&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;, &#039;side-post&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nonavbar&#039; =&amp;gt; true, &#039;langmenu&#039; =&amp;gt; true, &#039;nocontextheader&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // My public page.&lt;br /&gt;
    &#039;mypublic&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;login&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;boost&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;login.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;langmenu&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    // Pages that appear in pop-up windows - no navigation, no blocks, no header.&lt;br /&gt;
    &#039;popup&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;contentonly.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofooter&#039; =&amp;gt; true, &#039;nonavbar&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // No blocks and minimal footer - used for legacy frame layouts only!&lt;br /&gt;
    &#039;frametop&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;contentonly.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofooter&#039; =&amp;gt; true, &#039;nocoursefooter&#039; =&amp;gt; true),&lt;br /&gt;
    ),&lt;br /&gt;
    // Embeded pages, like iframe/object embeded in moodleform - it needs as much space as possible.&lt;br /&gt;
    &#039;embedded&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;embedded.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array()&lt;br /&gt;
    ),&lt;br /&gt;
    // Used during upgrade and install, and for the &#039;This site is undergoing maintenance&#039; message.&lt;br /&gt;
    // This must not have any blocks, links, or API calls that would lead to database or cache interaction.&lt;br /&gt;
    // Please be extremely careful if you are modifying this layout.&lt;br /&gt;
    &#039;maintenance&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;maintenance.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
    ),&lt;br /&gt;
    // Should display the content and basic headers only.&lt;br /&gt;
    &#039;print&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;contentonly.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
        &#039;options&#039; =&amp;gt; array(&#039;nofooter&#039; =&amp;gt; true, &#039;nonavbar&#039; =&amp;gt; false),&lt;br /&gt;
    ),&lt;br /&gt;
    // The pagelayout used when a redirection is occuring.&lt;br /&gt;
    &#039;redirect&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;embedded.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(),&lt;br /&gt;
    ),&lt;br /&gt;
    // The pagelayout used for reports.&lt;br /&gt;
    &#039;report&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;columns.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
    // The pagelayout used for safebrowser and securewindow.&lt;br /&gt;
    &#039;secure&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;theme&#039; =&amp;gt; &#039;classic&#039;,&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;secure.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; array(&#039;side-pre&#039;),&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;&lt;br /&gt;
    )&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Ready set go! ===&lt;br /&gt;
If you have been following along - now we are at the point where we can actually install and test our new theme. Try it now by visiting the admin notifications page to install the new plugin, and then choosing the new theme from the theme selector.&lt;br /&gt;
&lt;br /&gt;
[[https://docs.moodle.org/en/Standard_themes#Theme_selector Theme selector]]&lt;br /&gt;
&lt;br /&gt;
When you choose the new theme - you will find that it looks exactly the same as Classic. At this point with our minimal configuration - we are inheriting almost everything from our parent theme including styles and templates. You will notice though that we don&#039;t inherit the settings from our parent theme.&lt;br /&gt;
&lt;br /&gt;
=== Setup your Sass files ===&lt;br /&gt;
Once you have a theme that has been installed into your Moodle setup it is time to start styling it. The core Boostrap scss is very well suited for customization using Sass variables and overriding component. On [https://getbootstrap.com/docs/4.3/getting-started/theming/#variable-defaults Get bootstrap.com] there is some documentation on Sass variables and in theme/boost/scss/boostrap/_variables.scss you will see the full list of variables that can be changed.&lt;br /&gt;
&lt;br /&gt;
Before we start the theme needs to be able to return the complete set of Sass files that are required for Moodle and our custom Sass. So as a start we will be editing the config again:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/picture/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This is the function that returns the SCSS source for the main file in our theme.&lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
    return theme_picture_get_main_scss_content($theme);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variable $THEME-&amp;gt;scss is configured to be a callback function that when called returns all the Scss source files from our parent theme and the picture theme. Once the callback function is defined our Theme&#039;s lib.php needs to contain the callback function.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/picture/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
	/**&lt;br /&gt;
 * Returns the main SCSS content.&lt;br /&gt;
 *&lt;br /&gt;
 * @param theme_config $theme The theme config object.&lt;br /&gt;
 * @return string All fixed Sass for this theme.&lt;br /&gt;
 */&lt;br /&gt;
function theme_picture_get_main_scss_content($theme) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    $scss = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
    $fs = get_file_storage();&lt;br /&gt;
&lt;br /&gt;
    // Main CSS - Get the CSS from theme Classic.&lt;br /&gt;
    $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/classic/scss/classic/pre.scss&#039;);&lt;br /&gt;
    $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/classic/scss/preset/default.scss&#039;);&lt;br /&gt;
    $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/classic/scss/classic/post.scss&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Pre CSS - this is loaded AFTER any prescss from the setting but before the main scss.&lt;br /&gt;
    $pre = file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/picture/scss/pre.scss&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Post CSS - this is loaded AFTER the main scss but before the extra scss from the setting.&lt;br /&gt;
    $post = file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/picture/scss/post.scss&#039;);&lt;br /&gt;
&lt;br /&gt;
    // Combine them together.&lt;br /&gt;
    return $pre . &amp;quot;\n&amp;quot; . $scss . &amp;quot;\n&amp;quot; . $post;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function theme_picture_get_main_scss_content uses the scss files from classic, the default.scss file from classic contains @import statements to include the files from theme Boost so we can be sure we have all the css we need.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/classic/scss/preset/default.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
// Import FontAwesome.&lt;br /&gt;
@import &amp;quot;fontawesome&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// Import All of Bootstrap&lt;br /&gt;
@import &amp;quot;bootstrap&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
// Import Core moodle CSS&lt;br /&gt;
@import &amp;quot;moodle&amp;quot;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To complete the setup all we need to do is create the pre.scss and post.scss files that will contain our Sass variables and other Css. The pre.scss file is the file that needs to be loaded first before the files from theme classic are imported. It will contain the variable we configure for things like fonts, colours and spacing. The post.scss file will contain all other custom css.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/picture/scss/pre.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
// We need larger buttons.&lt;br /&gt;
$btn-padding-y:         0.5rem !default;&lt;br /&gt;
$btn-padding-x:         1.1rem !default;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme/picture/scss/post.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
// We like our buttons very round.&lt;br /&gt;
.btn {&lt;br /&gt;
  border-radius: 1.078em;&lt;br /&gt;
  font-family: $font-family-sans-serif;&lt;br /&gt;
  font-size: 0.875em;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You might have noticed the &amp;quot;!default&amp;quot; statement after the variables in our pre.scss file. This means the variable is set if the variable has not been defined before. When inspecting the Bootstrap variables defined in theme/boost/scss/bootstrap/_variables.scss you will see all variable have a &amp;quot;!default&amp;quot; statement meaning we can change any variable!&lt;br /&gt;
&lt;br /&gt;
With the preset files in place we can select our theme from the available installed themes (If you did not do that already) and purge changes. You should be able to see the Classic 3 column layout and our round buttons.&lt;br /&gt;
&lt;br /&gt;
=== Adding custom settings to our theme ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
That&#039;s it for this tutorial, but there are [[:Category:Themes| more Themes docs]] to browse.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Themes]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Template:Moodle_3.7&amp;diff=55651</id>
		<title>Template:Moodle 3.7</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Template:Moodle_3.7&amp;diff=55651"/>
		<updated>2019-03-06T08:11:04Z</updated>

		<summary type="html">&lt;p&gt;Fox: Create template&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;span class=&amp;quot;small-info-right&amp;quot;&amp;gt;Moodle &amp;lt;span class=&amp;quot;text-big new&amp;quot;&amp;gt;3.7&amp;lt;/span&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;includeonly&amp;gt;[[Category:Moodle 3.7]]&amp;lt;/includeonly&amp;gt;&lt;br /&gt;
&amp;lt;noinclude&amp;gt;This template will categorise articles that include it into [[:Category:Moodle 3.7]].&amp;lt;/noinclude&amp;gt;&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.7&amp;diff=55650</id>
		<title>Category:Moodle 3.7</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.7&amp;diff=55650"/>
		<updated>2019-03-06T08:10:33Z</updated>

		<summary type="html">&lt;p&gt;Fox: Create category&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages that relate to the planning and development of Moodle 3.7 features.&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moving_your_theme_to_use_boost_as_a_parent_theme&amp;diff=55645</id>
		<title>Moving your theme to use boost as a parent theme</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moving_your_theme_to_use_boost_as_a_parent_theme&amp;diff=55645"/>
		<updated>2019-03-05T15:08:20Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* Upgrading a theme to use Boost as a parent theme. */ Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.6}}&lt;br /&gt;
{{Template:Themes}}&lt;br /&gt;
&lt;br /&gt;
== Key differences ==&lt;br /&gt;
&lt;br /&gt;
=== Bootstrap version differences ===&lt;br /&gt;
&lt;br /&gt;
The biggest difference between themes Bootstrapbase and Boost are the included [http://getbootstrap.com Bootstrap] libraries. Bootstrapbase uses Bootstrap version 2.3.3, Boost uses Bootstrap version 4.0.0 (at the time of writing this document).&lt;br /&gt;
&lt;br /&gt;
=== CSS extension language differences ===&lt;br /&gt;
&lt;br /&gt;
[http://lesscss.org/ LESS css] is used in Bootstrapbase, Boost uses [https://sass-lang.com/ Sass CSS].&lt;br /&gt;
&lt;br /&gt;
LESS uses a different css syntax than Sass. The most obvious difference is the way variables are defined; LESS uses @, Sass uses $. There are many other differences between LESS and Sass; [https://css-tricks.com/sass-vs-less/ css-tricks] has more information on these differences. The npm package [https://www.npmjs.com/package/less2sass less2sass] can be helpful when migrating your less files.&lt;br /&gt;
&lt;br /&gt;
LESS css is compiled using a core [https://docs.moodle.org/dev/Grunt grunt] task and stored in theme/bootstrapbase/style/moodle.css. Child themes need to specify additional stylesheets using the &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;sheets = []&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
array or use &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;lessfile = &#039;&#039;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
to use the core [https://github.com/oyejorge/LESS.php LESScss] library&lt;br /&gt;
&lt;br /&gt;
Sass css is compiled using a core [http://leafo.github.io/scssphp scssphp] Library for theme Boost and child themes if &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;scss = &#039;&#039; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
is used. The compiled css file served to the end user is stored in a Moodle cache and is regenerated each time theme caches are cleared. Using the core scssphp compiler allows for the usage of [https://docs.moodle.org/dev/Boost_Presets Boost Presets]. For information on advanced usage of Sass css see the [https://docs.moodle.org/dev/SCSS SCSS] doc page.&lt;br /&gt;
&lt;br /&gt;
=== Moodle templates differences ===&lt;br /&gt;
&lt;br /&gt;
Theme Boost uses [https://docs.moodle.org/dev/Templates Templates] to render the main layouts. For each of the layout files in theme/boost/layouts/ there is a corresponding layout file in theme/boost/templates.&lt;br /&gt;
&lt;br /&gt;
The layout files found in theme Bootstrapbase are a combination of php and html.&lt;br /&gt;
&lt;br /&gt;
=== Renderers differences ===&lt;br /&gt;
&lt;br /&gt;
In theme Boost all overridden renderers can be found theme/boost/classes/output, in theme Bootstrapbase the overridden renderers are called in /theme/bootstrapbase/renderers.php.&lt;br /&gt;
&lt;br /&gt;
=== Theme config differences ===&lt;br /&gt;
&lt;br /&gt;
The theme configuration for Boost based themes do not differ much from Bootstrapbase based themes. For a full list of option is available in the [https://docs.moodle.org/dev/Themes_overview#Appendix_A Themes Overview] doc page.&lt;br /&gt;
&lt;br /&gt;
These configuration options only apply to theme Bootstrapbase and child themes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;lessfile = &#039;moodle&#039;;&lt;br /&gt;
$THEME-&amp;gt;lessvariablescallback = &#039;theme_more_less_variables&#039;;&lt;br /&gt;
$THEME-&amp;gt;extralesscallback = &#039;theme_more_extra_less&#039;;&lt;br /&gt;
$THEME-&amp;gt;doctype = &#039;html5&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These configuration options only apply to theme Boost and child themes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
    return theme_boost_get_main_scss_content($theme);&lt;br /&gt;
};&lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_boost_get_extra_scss&#039;;&lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_boost_get_pre_scss&#039;;&lt;br /&gt;
$THEME-&amp;gt;precompiledcsscallback = &#039;theme_boost_get_precompiled_css&#039;;&lt;br /&gt;
$THEME-&amp;gt;addblockposition = BLOCK_ADDBLOCK_POSITION_FLATNAV;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Upgrading a theme to use Boost as a parent theme. ==&lt;br /&gt;
&lt;br /&gt;
There is no fit-for-all tutorial on upgrading your theme since themes can have lots of custom features. The steps specified here are the steps that were taken upgrading the community theme [https://moodle.org/plugins/theme_elegance Elegance] to use theme Boost as its parent and serve as an example.&lt;br /&gt;
&lt;br /&gt;
=== Update the theme config ===&lt;br /&gt;
&lt;br /&gt;
Most of the config file can remain the same. References to less files need to be removed, the theme scss content needs to be specified using a callback.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
    return theme_elegance_get_main_scss_content($theme);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;code snippet from theme/elegance/config.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In this example the theme was specialised in rendering custom widgets on the front page, so we only need to specify a different layout file for the front page.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;layouts[&#039;frontpage&#039;] = [&lt;br /&gt;
        &#039;file&#039; =&amp;gt; &#039;frontpage.php&#039;,&lt;br /&gt;
        &#039;regions&#039; =&amp;gt; [&#039;side-pre&#039;],&lt;br /&gt;
        &#039;defaultregion&#039; =&amp;gt; &#039;side-pre&#039;,&lt;br /&gt;
        &#039;options&#039; =&amp;gt; [&#039;nonavbar&#039;],&lt;br /&gt;
    ];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;code snippet from theme/elegance/config.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Update the theme lib file ===&lt;br /&gt;
&lt;br /&gt;
Add the get_main_scss_content callback function to your theme lib file.&lt;br /&gt;
&lt;br /&gt;
The callback function will need to fetch the Sass files from your parent theme. Use this example when basing your theme of Boost&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Returns the main SCSS content.&lt;br /&gt;
 *&lt;br /&gt;
 * @param theme_config $theme The theme config object.&lt;br /&gt;
 * @return string&lt;br /&gt;
 */&lt;br /&gt;
function theme_elegance_get_main_scss_content($theme) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    $scss = file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/elegance/scss/variables.scss&#039;);&lt;br /&gt;
    $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/fontawesome.scss&#039;);&lt;br /&gt;
    $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/bootstrap.scss&#039;);&lt;br /&gt;
    $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/moodle.scss&#039;);&lt;br /&gt;
    $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/elegance/scss/post.scss&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $scss;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;code snippet from theme/elegance/lib.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Make sure your create these files when using the example above:&lt;br /&gt;
&lt;br /&gt;
* theme/elegance/scss/variables.scss&lt;br /&gt;
* theme/elegance/scss/post.scss&lt;br /&gt;
&lt;br /&gt;
=== Create your template and layout files ===&lt;br /&gt;
&lt;br /&gt;
If your theme contains custom layouts it will need a template for each layout. &lt;br /&gt;
&lt;br /&gt;
For theme elegance these layout files and templates were copied&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
cp theme/boost/layout/columns2.php theme/elegance/layout/frontpage.php&lt;br /&gt;
cp theme/boost/templates/columns2.mustache theme/elegance/templates/layout_frontpage.mustache&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
in the new frontpage.php the reference to the template needs updating after copying these:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    echo $OUTPUT-&amp;gt;render_from_template(&#039;theme_elegance/layout_frontpage&#039;, $templatecontext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;code snippet from theme/elegance/layout/frontpage.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Now the layout file and the template file are in place custom widget / renderers can be added for the front page.&lt;br /&gt;
&lt;br /&gt;
For theme elegance a carousel slideshow can be configured through the theme settings. The renderer for this carousel is called in theme/elegance/layout/frontpage.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$renderer = $PAGE-&amp;gt;get_renderer(&#039;theme_elegance&#039;);&lt;br /&gt;
$carousel = new \theme_elegance\output\carousel();&lt;br /&gt;
$widgets = (object) [&lt;br /&gt;
    &#039;carousel&#039; =&amp;gt; $renderer-&amp;gt;render($carousel)&lt;br /&gt;
];&lt;br /&gt;
&lt;br /&gt;
$templatecontext = [&lt;br /&gt;
    ..&lt;br /&gt;
    &#039;widgets&#039; =&amp;gt; $widgets,&lt;br /&gt;
    ..&lt;br /&gt;
];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;code snippet from theme/elegance/layout/frontpage.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The carousel widget is passed on to the theme/elegance/template/layout_frontpage.mustache template&lt;br /&gt;
&lt;br /&gt;
=== Migrating your LESS files ===&lt;br /&gt;
&lt;br /&gt;
The Bootstrapbase theme css is written in the [http://lesscss.org/ LESS css extention language]. Some child themes of bootstrapbase use LESS to generate their stylesheets. Usually these files are stored in the less/ folder of the child theme.&lt;br /&gt;
&lt;br /&gt;
The Boost theme css is written in the [https://sass-lang.com/ Sass css extention language]. A child theme can extend the Boost Sass files which are usually found in the sass/ folder of the child theme.&lt;br /&gt;
&lt;br /&gt;
The LESS and Sass extention languages are different and not compatible,  themes using less will have to migrate their stylesheets. This can be done manually or with the [https://www.npmjs.com/package/less2sass less2sass] tool to translate LESS files into Sass. This tool is a great start when migrating your LESS however, after running less2sass to migrate your stylesheets you will need to inspect them and fix them if needed.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
/* Icon styles */&lt;br /&gt;
// Size of big icons.&lt;br /&gt;
@icon-big-width: 64px;&lt;br /&gt;
@icon-big-height: 64px;&lt;br /&gt;
&lt;br /&gt;
img.icon {&lt;br /&gt;
    &amp;amp;.iconsize-big {&lt;br /&gt;
        width: @icon-big-width;&lt;br /&gt;
        height: @icon-big-height;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
.groupinfobox {&lt;br /&gt;
    .well;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;example less from theme/bootstrapbase/less/moodle/core.less&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
// Size of big icons.&lt;br /&gt;
$icon-big-width: 64px;&lt;br /&gt;
$icon-big-height: 64px;&lt;br /&gt;
.icon {&lt;br /&gt;
    &amp;amp;.iconsize-big {&lt;br /&gt;
        width: $icon-big-width;&lt;br /&gt;
        height: $icon-big-height;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
 .groupinfobox {&lt;br /&gt;
    @extend .card;&lt;br /&gt;
 }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;example sass from theme/boost/scss/moodle_core.scss&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The [https://sass-lang.com/ Sass CSS] extension language is not that hard to learn. Make sure you have read [https://sass-lang.com/guide The Sass Basics] and understand how to define and override variables and use mixins.&lt;br /&gt;
&lt;br /&gt;
When you start migrating your LESS file a good starting point is your theme variables.less. Usually child themes define a number of new variables and override some of the variables defined in theme/bootstrapbase/less/bootstrap/variables.less.&lt;br /&gt;
Your new variables will probably be okay when migrating to SASS. The overridden bootstrap variables will no longer be valid. So for each overridden variable try to find the new variables name in theme/boost/sass/bootstrap/_variables.scss.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
// Scaffolding&lt;br /&gt;
// -------------------------&lt;br /&gt;
@bodyBackground:        @white;&lt;br /&gt;
@textColor:             @grayDark;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
// Links&lt;br /&gt;
// -------------------------&lt;br /&gt;
@linkColor:             #08c;&lt;br /&gt;
@linkColorHover:        darken(@linkColor, 15%);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;example variables from theme/bootstrapbase/less/bootstrap/variables.less&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code css&amp;gt;&lt;br /&gt;
// Body&lt;br /&gt;
//&lt;br /&gt;
// Settings for the `&amp;lt;body&amp;gt;` element.&lt;br /&gt;
&lt;br /&gt;
$body-bg:                   $white !default;&lt;br /&gt;
$body-color:                $gray-900 !default;&lt;br /&gt;
&lt;br /&gt;
// Links&lt;br /&gt;
//&lt;br /&gt;
// Style anchor elements.&lt;br /&gt;
&lt;br /&gt;
$link-color:                theme-color(&amp;quot;primary&amp;quot;) !default;&lt;br /&gt;
$link-decoration:           none !default;&lt;br /&gt;
$link-hover-color:          darken($link-color, 15%) !default;&lt;br /&gt;
$link-hover-decoration:     underline !default;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;example variables form theme/boost/sass/bootstrap/_variables.scss&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Using grunt to debug Sass compile issues ===&lt;br /&gt;
&lt;br /&gt;
When you start creating your new Sass files debugging what happens in the Moodle core PHP Sass compiler can take a lot of time. The compiler is run using a caching mechanism and error reporting is poor, when a variable is misspelled the errors are send to your webserver logfiles.&lt;br /&gt;
&lt;br /&gt;
To speed up development The [http://gruntjs.com/ Grunt] Javascript taskrunner that runs on [https://nodejs.org/en/ Node.js] can be very helpful. If you have not tried to get Grunt running for Moodle core tasks make sure you read the [https://docs.moodle.org/dev/Grunt Moodle Grunt] docs page for more info.&lt;br /&gt;
&lt;br /&gt;
You can use Grunt to compile your Sass and check your Sass syntaxs. Once you have Grunt and Node.js up and running you can create your own Gruntfile.js and package.json file.&lt;br /&gt;
&lt;br /&gt;
For theme Elegance these files are found in [https://github.com/bmbrands/moodle-theme_elegance/blob/MOODLE_36_STABLE/Gruntfile.js theme/elegance/Gruntfile.js] and [https://github.com/bmbrands/moodle-theme_elegance/blob/MOODLE_36_STABLE/postcss.js theme/elegance/package.json].&lt;br /&gt;
&lt;br /&gt;
You can copy these into your theme folder and run the Node installer to retreive all Node dependancies.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code bash&amp;gt;&lt;br /&gt;
&amp;gt; nmp install&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Make sure you update the Gruntfile.js to reflect your configuration:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    sass: {&lt;br /&gt;
        options: {&lt;br /&gt;
            style: &#039;expanded&#039;&lt;br /&gt;
        },&lt;br /&gt;
        dist: {&lt;br /&gt;
            files: {&lt;br /&gt;
                &#039;style/elegance.css&#039;: &#039;scss/gruntcompile.scss&#039;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;section of the Grunfile.js you will need to change&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Once all dependancies are installed you can run Grunt to watch your Sass files. Each time you make a change in any of the files the the Node compiler will run and create a new stylesheet in your theme&#039;s style/ folder&lt;br /&gt;
&lt;br /&gt;
This stylesheet will not be served to the end user unless you change your theme configuration:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;sheets = [&#039;elegance&#039;];&lt;br /&gt;
&lt;br /&gt;
// Commented out to prevent PHP Sass compiling.&lt;br /&gt;
//$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
//    return theme_elegance_get_main_scss_content($theme);&lt;br /&gt;
//};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;section of theme/elegance/config.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Migrating your renderer files ===&lt;br /&gt;
&lt;br /&gt;
In Bootstrapbase the overriden renderers were located in theme/boost/renderers/. These renderes are stored in classes/output in the Boost.&lt;br /&gt;
&lt;br /&gt;
In theme Boost the overridden core renderer is located in theme/boost/classes/output/core_renderer.php. If your theme overrides the core renderer (/lib/outputrenderers.php) make sure you override the Boost renderer (In Moodle version 3.6 and below).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// This file is part of the elegance theme for Moodle&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
namespace theme_elegance\output;&lt;br /&gt;
&lt;br /&gt;
use \theme_boost\output\core_renderer as boost_core_renderer;&lt;br /&gt;
use stdClass;&lt;br /&gt;
use theme_config;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Renderers to align Moodle&#039;s HTML with that expected by Bootstrap&lt;br /&gt;
 *&lt;br /&gt;
 * @package    theme_elegance&lt;br /&gt;
 * @copyright  2019 Bas Brands&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
class core_renderer extends boost_core_renderer {&lt;br /&gt;
	 /**&lt;br /&gt;
     * Returns the title to use on the page.&lt;br /&gt;
     *&lt;br /&gt;
     * @since Moodle 2.5.1 2.6&lt;br /&gt;
     * @return string&lt;br /&gt;
     */&lt;br /&gt;
    public function page_title() {&lt;br /&gt;
        ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Move your custom renderers or other overridden renderes to your themes classes/output folder too.&lt;br /&gt;
&lt;br /&gt;
[[Category:Themes]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Releases&amp;diff=55248</id>
		<title>Releases</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Releases&amp;diff=55248"/>
		<updated>2018-12-10T13:30:21Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* General release calendar */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page lists all official releases of Moodle, grouped by branch in reverse chronological order.&lt;br /&gt;
&lt;br /&gt;
==Version support==&lt;br /&gt;
&lt;br /&gt;
From Moodle 2.6 onwards, the end of support, both general and security, happens the second Monday of May and November, observing the 12, 18... month periods, no matter if the major release was delayed or not.&lt;br /&gt;
&lt;br /&gt;
The most recent [https://en.wikipedia.org/wiki/Long-term_support long-term support release (LTS)] version is Moodle 3.5.&lt;br /&gt;
&lt;br /&gt;
[[Image:releasescurrent.png]]&lt;br /&gt;
&lt;br /&gt;
==General release calendar==&lt;br /&gt;
&lt;br /&gt;
These are the target dates for releases. These dates may vary slightly due to unforeseen circumstances.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Release type&lt;br /&gt;
! Frequency&lt;br /&gt;
! Months&lt;br /&gt;
|-&lt;br /&gt;
| [[Process#Major_release_cycles|Major]] (eg. 3.x)&lt;br /&gt;
| 6 monthly&lt;br /&gt;
| Second Monday of May and November&lt;br /&gt;
|-&lt;br /&gt;
| [[Process#Stable_maintenance_cycles|Minor]] (Point) (eg. 3.x.y)&lt;br /&gt;
| 2 monthly&lt;br /&gt;
| Second Monday of July, September, November, January, March and May&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All releases are preceded by a one week warning. Upcoming release dates can be found in the [https://www.google.com/calendar/ical/moodle.com_p4c2oe7hsb77ltaro5qtihb5d4%40group.calendar.google.com/public/basic.ics Moodle development calendar] (Note, this is an iCAL link that will try to add the dates to your personal calendar. If you just want to browse the dates online, use [https://calendar.google.com/calendar/embed?src=moodle.com_p4c2oe7hsb77ltaro5qtihb5d4@group.calendar.google.com&amp;amp;pli=1 this link].).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.6==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6&lt;br /&gt;
| 3 December 2018&lt;br /&gt;
| 2018120300&lt;br /&gt;
| [[Moodle 3.6 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/36/en/Upgrading Upgrading to 3.6]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.6.1&lt;br /&gt;
| 5 December 2018&lt;br /&gt;
| 2018120301&lt;br /&gt;
| [[Moodle 3.6.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.6.x will end 11 November 2019 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.6.x will end 11 May 2020 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.5 (LTS)==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2018051700&lt;br /&gt;
| [[Moodle 3.5 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/35/en/Upgrading Upgrading to 3.5]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.1&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2018051701&lt;br /&gt;
| [[Moodle 3.5.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.2&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2018051702&lt;br /&gt;
| [[Moodle 3.5.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.5.3&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2018051703&lt;br /&gt;
| [[Moodle 3.5.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.5.x will end 13 May 2019 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.5.x will end 10 May 2021 (36 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.4==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2017111300&lt;br /&gt;
| [[Moodle 3.4 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/34/en/Upgrading Upgrading to 3.4]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.1&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2017111301&lt;br /&gt;
| [[Moodle 3.4.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.2&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2017111302&lt;br /&gt;
| [[Moodle 3.4.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.3&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2017111303&lt;br /&gt;
| [[Moodle 3.4.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.4&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2017111304&lt;br /&gt;
| [[Moodle 3.4.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.5&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2017111305&lt;br /&gt;
| [[Moodle 3.4.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.4.6&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2017111306&lt;br /&gt;
| [[Moodle 3.4.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.4.x ended 12 November 2018 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.4.x will end 13 May 2019 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.3==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3&lt;br /&gt;
| 15 May 2017&lt;br /&gt;
| 2017051500&lt;br /&gt;
| [[Moodle 3.3 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/33/en/Upgrading Upgrading to 3.3]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.1&lt;br /&gt;
| 10 July 2017&lt;br /&gt;
| 2017051501&lt;br /&gt;
| [[Moodle 3.3.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.2&lt;br /&gt;
| 11 September 2017&lt;br /&gt;
| 2017051502&lt;br /&gt;
| [[Moodle 3.3.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.3&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2017051503&lt;br /&gt;
| [[Moodle 3.3.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.4&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2017051504&lt;br /&gt;
| [[Moodle 3.3.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.5&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2017051505&lt;br /&gt;
| [[Moodle 3.3.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.6&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2017051506&lt;br /&gt;
| [[Moodle 3.3.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.7&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2017051507&lt;br /&gt;
| [[Moodle 3.3.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.8&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2017051508&lt;br /&gt;
| [[Moodle 3.3.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.3.9&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2017051509&lt;br /&gt;
| [[Moodle 3.3.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.3.x ended 17 May 2018 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.3.x ended 12 November 2018 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.2==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2&lt;br /&gt;
| 5 December 2016&lt;br /&gt;
| 2016120500&lt;br /&gt;
| [[Moodle 3.2 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/32/en/Upgrading Upgrading to 3.2]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.1&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2016120501&lt;br /&gt;
| [[Moodle 3.2.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.2&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2016120502&lt;br /&gt;
| [[Moodle 3.2.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.3&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2016120503&lt;br /&gt;
| [[Moodle 3.2.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.4&lt;br /&gt;
| 10 July 2017&lt;br /&gt;
| 2016120504&lt;br /&gt;
| [[Moodle 3.2.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.5&lt;br /&gt;
| 11 September 2017&lt;br /&gt;
| 2016120505&lt;br /&gt;
| [[Moodle 3.2.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.6&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2016120506&lt;br /&gt;
| [[Moodle 3.2.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.7&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2016120507&lt;br /&gt;
| [[Moodle 3.2.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.8&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2016120508&lt;br /&gt;
| [[Moodle 3.2.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.2.9&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2016120509&lt;br /&gt;
| [[Moodle 3.2.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.2.x ended 13 November 2017 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.2.x ended 17 May 2018 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.1 (LTS)==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1&lt;br /&gt;
| 23 May 2016&lt;br /&gt;
| 2016052300&lt;br /&gt;
| [[Moodle 3.1 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/31/en/Upgrading Upgrading to 3.1]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.1&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2016052301&lt;br /&gt;
| [[Moodle 3.1.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.2&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2016052302&lt;br /&gt;
| [[Moodle 3.1.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.3&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2016052303&lt;br /&gt;
| [[Moodle 3.1.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.4&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2016052304&lt;br /&gt;
| [[Moodle 3.1.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.5&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2016052305&lt;br /&gt;
| [[Moodle 3.1.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.6&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2016052306&lt;br /&gt;
| [[Moodle 3.1.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.7&lt;br /&gt;
| 10 July 2017&lt;br /&gt;
| 2016052307&lt;br /&gt;
| [[Moodle 3.1.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.8&lt;br /&gt;
| 11 September 2017&lt;br /&gt;
| 2016052308&lt;br /&gt;
| [[Moodle 3.1.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.9&lt;br /&gt;
| 13 November 2017&lt;br /&gt;
| 2016052309&lt;br /&gt;
| [[Moodle 3.1.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.10&lt;br /&gt;
| 15 January 2018&lt;br /&gt;
| 2016052310&lt;br /&gt;
| [[Moodle 3.1.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.11&lt;br /&gt;
| 19 March 2018&lt;br /&gt;
| 2016052311&lt;br /&gt;
| [[Moodle 3.1.11 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.12&lt;br /&gt;
| 17 May 2018&lt;br /&gt;
| 2016052312&lt;br /&gt;
| [[Moodle 3.1.12 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.13&lt;br /&gt;
| 9 July 2018&lt;br /&gt;
| 2016052313&lt;br /&gt;
| [[Moodle 3.1.13 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.14&lt;br /&gt;
| 10 September 2018&lt;br /&gt;
| 2016052314&lt;br /&gt;
| [[Moodle 3.1.14 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.1.15&lt;br /&gt;
| 12 November 2018&lt;br /&gt;
| 2016052315&lt;br /&gt;
| [[Moodle 3.1.15 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.1.x ended 8 May 2017 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.1.x will end 13 May 2019 (36 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 3.0==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0&lt;br /&gt;
| 16 November 2015&lt;br /&gt;
| 2015111600&lt;br /&gt;
| [[Moodle 3.0 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/30/en/Upgrading Upgrading to 3.0]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.1&lt;br /&gt;
| 21 December 2015&lt;br /&gt;
| 2015111601&lt;br /&gt;
| [[Moodle 3.0.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.2&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2015111602&lt;br /&gt;
| [[Moodle 3.0.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.3&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2015111603&lt;br /&gt;
| [[Moodle 3.0.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.4&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2015111604&lt;br /&gt;
| [[Moodle 3.0.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.5&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2015111605&lt;br /&gt;
| [[Moodle 3.0.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.6&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2015111606&lt;br /&gt;
| [[Moodle 3.0.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.7&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2015111607&lt;br /&gt;
| [[Moodle 3.0.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.8&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2015111608&lt;br /&gt;
| [[Moodle 3.0.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.9&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2015111609&lt;br /&gt;
| [[Moodle 3.0.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 3.0.10&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2015111610&lt;br /&gt;
| [[Moodle 3.0.10 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 3.0.x ended 14 November 2016 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 3.0.x ended 8 May 2017 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.9==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2015051100&lt;br /&gt;
| [[Moodle 2.9 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/29/en/Upgrading_to_Moodle_2.9 Upgrading to 2.9]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.1&lt;br /&gt;
| 6 July 2015&lt;br /&gt;
| 2015051101&lt;br /&gt;
| [[Moodle 2.9.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.2&lt;br /&gt;
| 14 September 2015&lt;br /&gt;
| 2015051102&lt;br /&gt;
| [[Moodle 2.9.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.3&lt;br /&gt;
| 9 November 2015&lt;br /&gt;
| 2015051103&lt;br /&gt;
| [[Moodle 2.9.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.4&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2015051104&lt;br /&gt;
| [[Moodle 2.9.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.5&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2015051105&lt;br /&gt;
| [[Moodle 2.9.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.6&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2015051106&lt;br /&gt;
| [[Moodle 2.9.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.7&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2015051107&lt;br /&gt;
| [[Moodle 2.9.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.8&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2015051108&lt;br /&gt;
| [[Moodle 2.9.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.9.9&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2015051109&lt;br /&gt;
| [[Moodle 2.9.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.9.x ended 9 May 2016 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.9.x ended 14 November 2016 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.8==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2014111000&lt;br /&gt;
| [[Moodle 2.8 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/28/en/Upgrading_to_Moodle_2.8 Upgrading to 2.8]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.1&lt;br /&gt;
| 13 November 2014&lt;br /&gt;
| 2014111001&lt;br /&gt;
| [[Moodle 2.8.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.2&lt;br /&gt;
| 12 January 2015&lt;br /&gt;
| 2014111002&lt;br /&gt;
| [[Moodle 2.8.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.3&lt;br /&gt;
| 2 February 2015&lt;br /&gt;
| 2014111003&lt;br /&gt;
| [[Moodle 2.8.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.4&lt;br /&gt;
| 9 March 2015&lt;br /&gt;
| 2014111004&lt;br /&gt;
| [[Moodle 2.8.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.5&lt;br /&gt;
| 10 March 2015&lt;br /&gt;
| 2014111005&lt;br /&gt;
| [[Moodle 2.8.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.6&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2014111006&lt;br /&gt;
| [[Moodle 2.8.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.7&lt;br /&gt;
| 6 July 2015&lt;br /&gt;
| 2014111007&lt;br /&gt;
| [[Moodle 2.8.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.8&lt;br /&gt;
| 14 September 2015&lt;br /&gt;
| 2014111008&lt;br /&gt;
| [[Moodle 2.8.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.9&lt;br /&gt;
| 9 November 2015&lt;br /&gt;
| 2014111009&lt;br /&gt;
| [[Moodle 2.8.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.10&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2014111010&lt;br /&gt;
| [[Moodle 2.8.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.11&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2014111011&lt;br /&gt;
| [[Moodle 2.8.11 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.8.12&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2014111012&lt;br /&gt;
| [[Moodle 2.8.12 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.8.x ended 9 November 2015 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.8.x ended 9 May 2016 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.7 (LTS)==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2014051200&lt;br /&gt;
| [[Moodle 2.7 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/27/en/Upgrading_to_Moodle_2.7 Upgrading to 2.7]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.1&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2014051201&lt;br /&gt;
| [[Moodle 2.7.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.2&lt;br /&gt;
| 8 September 2014&lt;br /&gt;
| 2014051202&lt;br /&gt;
| [[Moodle 2.7.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.3&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2014051203&lt;br /&gt;
| [[Moodle 2.7.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.4&lt;br /&gt;
| 12 January 2015&lt;br /&gt;
| 2014051204&lt;br /&gt;
| [[Moodle 2.7.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.5&lt;br /&gt;
| 2 February 2015&lt;br /&gt;
| 2014051205&lt;br /&gt;
| [[Moodle 2.7.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.6&lt;br /&gt;
| 9 March 2015&lt;br /&gt;
| 2014051206&lt;br /&gt;
| [[Moodle 2.7.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.7&lt;br /&gt;
| 10 March 2015&lt;br /&gt;
| 2014051207&lt;br /&gt;
| [[Moodle 2.7.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.8&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2014051208&lt;br /&gt;
| [[Moodle 2.7.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.9&lt;br /&gt;
| 6 July 2015&lt;br /&gt;
| 2014051209&lt;br /&gt;
| [[Moodle 2.7.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.10&lt;br /&gt;
| 14 September 2015&lt;br /&gt;
| 2014051210&lt;br /&gt;
| [[Moodle 2.7.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.11&lt;br /&gt;
| 9 November 2015&lt;br /&gt;
| 2014051211&lt;br /&gt;
| [[Moodle 2.7.11 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.12&lt;br /&gt;
| 11 January 2016&lt;br /&gt;
| 2014051212&lt;br /&gt;
| [[Moodle 2.7.12 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.13&lt;br /&gt;
| 14 March 2016&lt;br /&gt;
| 2014051213&lt;br /&gt;
| [[Moodle 2.7.13 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.14&lt;br /&gt;
| 9 May 2016&lt;br /&gt;
| 2014051214&lt;br /&gt;
| [[Moodle 2.7.14 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.15&lt;br /&gt;
| 11 July 2016&lt;br /&gt;
| 2014051215&lt;br /&gt;
| [[Moodle 2.7.15 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.16&lt;br /&gt;
| 12 September 2016&lt;br /&gt;
| 2014051216&lt;br /&gt;
| [[Moodle 2.7.16 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.17&lt;br /&gt;
| 14 November 2016&lt;br /&gt;
| 2014051217&lt;br /&gt;
| [[Moodle 2.7.17 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.18&lt;br /&gt;
| 9 January 2017&lt;br /&gt;
| 2014051218&lt;br /&gt;
| [[Moodle 2.7.18 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.19&lt;br /&gt;
| 13 March 2017&lt;br /&gt;
| 2014051219&lt;br /&gt;
| [[Moodle 2.7.19 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.7.20&lt;br /&gt;
| 8 May 2017&lt;br /&gt;
| 2014051220&lt;br /&gt;
| [[Moodle 2.7.20 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.7.x ended 11 May 2015 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.7.x ended 8 May 2017 (36 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.6==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6&lt;br /&gt;
| 18 November 2013&lt;br /&gt;
| 2013111800&lt;br /&gt;
| [[Moodle 2.6 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/26/en/Upgrading_to_Moodle_2.6 Upgrading to 2.6]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.1&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2013111801&lt;br /&gt;
| [[Moodle 2.6.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.2&lt;br /&gt;
| 10 March 2014&lt;br /&gt;
| 2013111802&lt;br /&gt;
| [[Moodle 2.6.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.3&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2013111803&lt;br /&gt;
| [[Moodle 2.6.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.4&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2013111804&lt;br /&gt;
| [[Moodle 2.6.4 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.5&lt;br /&gt;
| 8 September 2014&lt;br /&gt;
| 2013111805&lt;br /&gt;
| [[Moodle 2.6.5 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.6&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2013111806&lt;br /&gt;
| [[Moodle 2.6.6 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.7&lt;br /&gt;
| 12 January 2015&lt;br /&gt;
| 2013111807&lt;br /&gt;
| [[Moodle 2.6.7 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.8&lt;br /&gt;
| 2 February 2015&lt;br /&gt;
| 2013111808&lt;br /&gt;
| [[Moodle 2.6.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.9&lt;br /&gt;
| 9 March 2015&lt;br /&gt;
| 2013111809&lt;br /&gt;
| [[Moodle 2.6.9 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.10&lt;br /&gt;
| 10 March 2015&lt;br /&gt;
| 2013111810&lt;br /&gt;
| [[Moodle 2.6.10 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.6.11&lt;br /&gt;
| 11 May 2015&lt;br /&gt;
| 2013111811&lt;br /&gt;
| [[Moodle 2.6.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.6.x ended 10 November 2014 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.6.x ended 11 May 2015 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.5==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2013051400&lt;br /&gt;
| [[Moodle 2.5 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/25/en/Upgrading_to_Moodle_2.5 Upgrading to 2.5]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.1&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2013051401&lt;br /&gt;
| [[Moodle 2.5.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.2&lt;br /&gt;
| 9 September 2013&lt;br /&gt;
| 2013051402&lt;br /&gt;
| [[Moodle 2.5.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.3&lt;br /&gt;
| 11 November 2013&lt;br /&gt;
| 2013051403&lt;br /&gt;
| [[Moodle 2.5.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.4&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2013051404&lt;br /&gt;
| [[Moodle 2.5.4 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.5&lt;br /&gt;
| 10 March 2014&lt;br /&gt;
| 2013051405&lt;br /&gt;
| [[Moodle 2.5.5 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.6&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2013051406&lt;br /&gt;
| [[Moodle 2.5.6 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.7&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2013051407&lt;br /&gt;
| [[Moodle 2.5.7 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.8&lt;br /&gt;
| 8 September 2014&lt;br /&gt;
| 2013051408&lt;br /&gt;
| [[Moodle 2.5.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.5.9&lt;br /&gt;
| 10 November 2014&lt;br /&gt;
| 2013051409&lt;br /&gt;
| [[Moodle 2.5.9 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.5.x ended May 2014 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.5.x ended 10 November 2014 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.4==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4&lt;br /&gt;
| 3 December 2012&lt;br /&gt;
| 2012120300&lt;br /&gt;
| [[Moodle 2.4 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/24/en/Upgrading_to_Moodle_2.4 Upgrading to 2.4]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.1&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 2012120301&lt;br /&gt;
| [[Moodle 2.4.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.2&lt;br /&gt;
| 11 March 2013&lt;br /&gt;
| 2012120302&lt;br /&gt;
| [[Moodle 2.4.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.3&lt;br /&gt;
| 18 March 2013&lt;br /&gt;
| 2012120303&lt;br /&gt;
| [[Moodle 2.4.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.4&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2012120304&lt;br /&gt;
| [[Moodle 2.4.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.5&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2012120305&lt;br /&gt;
| [[Moodle 2.4.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.6&lt;br /&gt;
| 9 September 2013&lt;br /&gt;
| 2012120306&lt;br /&gt;
| [[Moodle 2.4.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.7&lt;br /&gt;
| 11 November 2013&lt;br /&gt;
| 2012120307&lt;br /&gt;
| [[Moodle 2.4.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.8&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2012120308&lt;br /&gt;
| [[Moodle 2.4.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.9&lt;br /&gt;
| 10 March 2014&lt;br /&gt;
| 2012120309&lt;br /&gt;
| [[Moodle 2.4.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.10&lt;br /&gt;
| 12 May 2014&lt;br /&gt;
| 2012120310&lt;br /&gt;
| [[Moodle 2.4.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.4.11&lt;br /&gt;
| 14 July 2014&lt;br /&gt;
| 2012120311&lt;br /&gt;
| [[Moodle 2.4.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.4.x ended December 2013 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.4.x ended June 2014 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.3==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3&lt;br /&gt;
| 25 June 2012&lt;br /&gt;
| 2012062500&lt;br /&gt;
| [[Moodle 2.3 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/23/en/Upgrading_to_Moodle_2.3 Upgrading to 2.3]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.1&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2012062501&lt;br /&gt;
| [[Moodle 2.3.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.2&lt;br /&gt;
| 10 September 2012&lt;br /&gt;
| 2012062502&lt;br /&gt;
| [[Moodle 2.3.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.3&lt;br /&gt;
| 12 November 2012&lt;br /&gt;
| 2012062503&lt;br /&gt;
| [[Moodle 2.3.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.4&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 2012062504&lt;br /&gt;
| [[Moodle 2.3.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.5&lt;br /&gt;
| 11 March 2013&lt;br /&gt;
| 2012062505&lt;br /&gt;
| [[Moodle 2.3.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.6&lt;br /&gt;
| 18 March 2013&lt;br /&gt;
| 2012062506&lt;br /&gt;
| [[Moodle 2.3.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.7&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2012062507&lt;br /&gt;
| [[Moodle 2.3.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.8&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2012062508&lt;br /&gt;
| [[Moodle 2.3.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.9&lt;br /&gt;
| 9 September 2013&lt;br /&gt;
| 2012062509&lt;br /&gt;
| [[Moodle 2.3.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.10&lt;br /&gt;
| 11 November 2013&lt;br /&gt;
| 2012062510&lt;br /&gt;
| [[Moodle 2.3.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.3.11&lt;br /&gt;
| 13 January 2014&lt;br /&gt;
| 2012062511&lt;br /&gt;
| [[Moodle 2.3.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.3.x ended June 2013 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.3.x ended December 2013 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.2==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2&lt;br /&gt;
| 5 December 2011&lt;br /&gt;
| 2011120500&lt;br /&gt;
| [[Moodle 2.2 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/22/en/Upgrading_to_Moodle_2.2 Upgrading to 2.2]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.1&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2011120501&lt;br /&gt;
| [[Moodle 2.2.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.2&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2011120502&lt;br /&gt;
| [[Moodle 2.2.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.3&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2011120503&lt;br /&gt;
| [[Moodle 2.2.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.4&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2011120504&lt;br /&gt;
| [[Moodle 2.2.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.5&lt;br /&gt;
| 10 September 2012&lt;br /&gt;
| 2011120505&lt;br /&gt;
| [[Moodle 2.2.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.6&lt;br /&gt;
| 12 November 2012&lt;br /&gt;
| 2011120506&lt;br /&gt;
| [[Moodle 2.2.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.7&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 2011120507&lt;br /&gt;
| [[Moodle 2.2.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.8&lt;br /&gt;
| 11 March 2013&lt;br /&gt;
| 2011120508&lt;br /&gt;
| [[Moodle 2.2.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.9&lt;br /&gt;
| 18 March 2013&lt;br /&gt;
| 2011120509&lt;br /&gt;
| [[Moodle 2.2.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.10&lt;br /&gt;
| 14 May 2013&lt;br /&gt;
| 2011120510&lt;br /&gt;
| [[Moodle 2.2.10 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.2.11&lt;br /&gt;
| 8 July 2013&lt;br /&gt;
| 2011120511&lt;br /&gt;
| [[Moodle 2.2.11 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.2.x ended December 2012 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.2.x ended June 2013 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.1==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1&lt;br /&gt;
| 1 July 2011&lt;br /&gt;
| 2011070100&lt;br /&gt;
| [[Moodle 2.1 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/21/en/Upgrading_to_Moodle_2.1 Upgrading to 2.1]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.1&lt;br /&gt;
| 1 August 2011&lt;br /&gt;
| 2011070101&lt;br /&gt;
| [[Moodle 2.1.1 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.2&lt;br /&gt;
| 10 October 2011&lt;br /&gt;
| 2011070102&lt;br /&gt;
| [[Moodle 2.1.2 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.3&lt;br /&gt;
| 28 November 2011&lt;br /&gt;
| 2011070103&lt;br /&gt;
| [[Moodle 2.1.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.4&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2011070104&lt;br /&gt;
| [[Moodle 2.1.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.5&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2011070105&lt;br /&gt;
| [[Moodle 2.1.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.6&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2011070106&lt;br /&gt;
| [[Moodle 2.1.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.7&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2011070107&lt;br /&gt;
| [[Moodle 2.1.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.8&lt;br /&gt;
| 10 September 2012&lt;br /&gt;
| 2011070108&lt;br /&gt;
| [[Moodle 2.1.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.9&lt;br /&gt;
| 12 November 2012&lt;br /&gt;
| 2011070109&lt;br /&gt;
| [[Moodle 2.1.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.1.10&lt;br /&gt;
| 14 January 2013&lt;br /&gt;
| 20110701010&lt;br /&gt;
| [[Moodle 2.1.10 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.1.x ended June 2012 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.1.x ended December 2012 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 2.0==&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0&lt;br /&gt;
| 24 November 2010&lt;br /&gt;
| 2010112400&lt;br /&gt;
| [[Moodle 2.0 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/20/en/Upgrading_to_Moodle_2.0 Upgrading to 2.0]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.1&lt;br /&gt;
| 25 December 2010&lt;br /&gt;
| 2010122500&lt;br /&gt;
| [[Moodle 2.0.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.2&lt;br /&gt;
| 21 February 2011&lt;br /&gt;
| 2011022100&lt;br /&gt;
| [[Moodle 2.0.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.3&lt;br /&gt;
| 5 May 2011&lt;br /&gt;
| 2011033003&lt;br /&gt;
| [[Moodle 2.0.3 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.4&lt;br /&gt;
| 1 August 2011&lt;br /&gt;
| 2011033004&lt;br /&gt;
| [[Moodle 2.0.4 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.5&lt;br /&gt;
| 10 October 2011&lt;br /&gt;
| 2011033005&lt;br /&gt;
| [[Moodle 2.0.5 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.6&lt;br /&gt;
| 28 November 2011&lt;br /&gt;
| 2011033006&lt;br /&gt;
| [[Moodle 2.0.6 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.7&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2011033007&lt;br /&gt;
| [[Moodle 2.0.7 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.8&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2011033008&lt;br /&gt;
| [[Moodle 2.0.8 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.9&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2011033009&lt;br /&gt;
| [[Moodle 2.0.9 release notes|Release Notes]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 2.0.10&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2011033010&lt;br /&gt;
| [[Moodle 2.0.10 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 2.0.x ended December 2011 (12 months).&lt;br /&gt;
 Bug fixes for security issues in 2.0.x ended June 2012 (18 months).&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.9==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9&lt;br /&gt;
| 3 March 2008&lt;br /&gt;
| 2007101509 &lt;br /&gt;
| [[Moodle 1.9 release notes|Release Notes]]&lt;br /&gt;
| [https://docs.moodle.org/19/en/Upgrading_to_Moodle_1.9 Upgrading to 1.9]&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.1&lt;br /&gt;
| 15 May 2008&lt;br /&gt;
| 2007101512 &lt;br /&gt;
| [[Moodle 1.9.1 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.2&lt;br /&gt;
| 11 July 2008&lt;br /&gt;
| 2007101520&lt;br /&gt;
| [[Moodle 1.9.2 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.3&lt;br /&gt;
| 15 October 2008&lt;br /&gt;
| 2007101530&lt;br /&gt;
| [[Moodle 1.9.3 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.4&lt;br /&gt;
| 28 January 2009&lt;br /&gt;
| 2007101540&lt;br /&gt;
| [[Moodle 1.9.4 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.5&lt;br /&gt;
| 13 May 2009&lt;br /&gt;
| 2007101550&lt;br /&gt;
| [[Moodle 1.9.5 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.6&lt;br /&gt;
| 21 October 2009&lt;br /&gt;
| 2007101560&lt;br /&gt;
| [[Moodle 1.9.6 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.7&lt;br /&gt;
| 25 November 2009&lt;br /&gt;
| 2007101570&lt;br /&gt;
| [[Moodle 1.9.7 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.8&lt;br /&gt;
| 25 March 2010&lt;br /&gt;
| 2007101580.00&lt;br /&gt;
| [[Moodle 1.9.8 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.9&lt;br /&gt;
| 8 June 2010&lt;br /&gt;
| 2007101590.00&lt;br /&gt;
| [[Moodle 1.9.9 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.10&lt;br /&gt;
| 25 October 2010&lt;br /&gt;
| 2007101591.00&lt;br /&gt;
| [[Moodle 1.9.10 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.11&lt;br /&gt;
| 21 February 2011&lt;br /&gt;
| 2007101591.02&lt;br /&gt;
| [[Moodle 1.9.11 release notes|Release Notes]] &lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.12&lt;br /&gt;
| 10 May 2011&lt;br /&gt;
| 2007101591.03&lt;br /&gt;
| [[Moodle 1.9.12 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.13&lt;br /&gt;
| 1 August 2011&lt;br /&gt;
| 2007101591.04&lt;br /&gt;
| [[Moodle 1.9.13 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.14&lt;br /&gt;
| 10 October 2011&lt;br /&gt;
| 2007101591.06&lt;br /&gt;
| [[Moodle 1.9.14 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.15&lt;br /&gt;
| 28 November 2011&lt;br /&gt;
| 2007101591.07&lt;br /&gt;
| [[Moodle 1.9.15 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.16&lt;br /&gt;
| 9 January 2012&lt;br /&gt;
| 2007101591.10&lt;br /&gt;
| [[Moodle 1.9.16 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.17&lt;br /&gt;
| 12 March 2012&lt;br /&gt;
| 2007101591.12&lt;br /&gt;
| [[Moodle 1.9.17 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.18&lt;br /&gt;
| 14 May 2012&lt;br /&gt;
| 2007101591.16&lt;br /&gt;
| [[Moodle 1.9.18 release notes|Release Notes]]&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
! Moodle 1.9.19&lt;br /&gt;
| 9 July 2012&lt;br /&gt;
| 2007101592.00&lt;br /&gt;
| [[Moodle 1.9.19 release notes|Release Notes]]&lt;br /&gt;
| Support has ended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
 Bug fixes for general core bugs in 1.9.x has ended June 2011 (3.5 years).&lt;br /&gt;
 Bug fixes for security issues in 1.9.x by Moodle HQ ended June 2012 (4.5 years).&lt;br /&gt;
 Bug fixes for security issues in 1.9.19+ branch by [http://catalyst.net.nz Catalyst IT] ended [http://moodle.org/mod/forum/discuss.php?d=199706 Dec 2013] (6 years).&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.8==&lt;br /&gt;
*[[Moodle 1.8 release notes|Moodle 1.8]] - 30 March 2007&lt;br /&gt;
*[[Moodle 1.8.1 release notes|Moodle 1.8.1]] - 14 June 2007&lt;br /&gt;
*[[Moodle 1.8.2 release notes|Moodle 1.8.2]] - 8 July 2007&lt;br /&gt;
*[[Moodle 1.8.3 release notes|Moodle 1.8.3]] - 11 October 2007&lt;br /&gt;
*[[Moodle 1.8.4 release notes|Moodle 1.8.4]] - 11 January 2008&lt;br /&gt;
*[[Moodle 1.8.5 release notes|Moodle 1.8.5]] - 8 April 2008&lt;br /&gt;
*[[Moodle 1.8.6 release notes|Moodle 1.8.6]] - 11 July 2008&lt;br /&gt;
*[[Moodle 1.8.7 release notes|Moodle 1.8.7]] - 15 October 2008&lt;br /&gt;
*[[Moodle 1.8.8 release notes|Moodle 1.8.8]] - 28 January 2009&lt;br /&gt;
*[[Moodle 1.8.9 release notes|Moodle 1.8.9]] - 15 May 2009&lt;br /&gt;
*[[Moodle 1.8.10 release notes|Moodle 1.8.10]] - 26 October 2009&lt;br /&gt;
*[[Moodle 1.8.11 release notes|Moodle 1.8.11]] - 25 November 2009&lt;br /&gt;
*[[Moodle 1.8.12 release notes|Moodle 1.8.12]] - 27 March 2010&lt;br /&gt;
*[[Moodle 1.8.13 release notes|Moodle 1.8.13]] - 8 June 2010&lt;br /&gt;
*[[Moodle 1.8.14 release notes|Moodle 1.8.14]] - 3 December 2010&lt;br /&gt;
*Support has ended &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.7==&lt;br /&gt;
*[[Moodle 1.7 release notes|Moodle 1.7]] - 7 November 2006&lt;br /&gt;
*[[Moodle 1.7.1 release notes|Moodle 1.7.1]] - 17 January 2007&lt;br /&gt;
*[[Moodle 1.7.2 release notes|Moodle 1.7.2]] - 30 March 2007&lt;br /&gt;
*[[Moodle 1.7.3 release notes|Moodle 1.7.3]] - 11 October 2007&lt;br /&gt;
*[[Moodle 1.7.4 release notes|Moodle 1.7.4]] - 11 January 2008&lt;br /&gt;
*[[Moodle 1.7.5 release notes|Moodle 1.7.5]] - 11 July 2008&lt;br /&gt;
*[[Moodle 1.7.6 release notes|Moodle 1.7.6]] - 15 October 2008&lt;br /&gt;
*[[Moodle 1.7.7 release notes|Moodle 1.7.7]] - 28 January 2009&lt;br /&gt;
*Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.6==&lt;br /&gt;
*[[Moodle 1.6 release notes|Moodle 1.6]] - 20 June 2006&lt;br /&gt;
*[[Moodle 1.6.1 release notes|Moodle 1.6.1]] - 20 July 2006&lt;br /&gt;
*[[Moodle 1.6.2 release notes|Moodle 1.6.2]] - 12 September 2006&lt;br /&gt;
*[[Moodle 1.6.3 release notes|Moodle 1.6.3]] - 10 October 2006&lt;br /&gt;
*[[Moodle 1.6.4 release notes|Moodle 1.6.4]] - 17 January 2007&lt;br /&gt;
*[[Moodle 1.6.5 release notes|Moodle 1.6.5]] - 30 March 2007&lt;br /&gt;
*Moodle 1.6.6 - 11 January 2008&lt;br /&gt;
*Moodle 1.6.7 - 11 July 2008&lt;br /&gt;
*[[Moodle 1.6.8 release notes|Moodle 1.6.8]] - 15 October 2008&lt;br /&gt;
*[[Moodle 1.6.9 release notes|Moodle 1.6.9]] - 28 January 2009&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.5==&lt;br /&gt;
*[[Moodle 1.5 release notes|Moodle 1.5]] - 5 June 2005&lt;br /&gt;
*[[Moodle 1.5.1 release notes|Moodle 1.5.1]] - 8 July 2005&lt;br /&gt;
*[[Moodle 1.5.2 release notes|Moodle 1.5.2]] - 16 July 2005&lt;br /&gt;
*[[Moodle 1.5.3 release notes|Moodle 1.5.3]] - 11 November 2005&lt;br /&gt;
*[[Moodle 1.5.4 release notes|Moodle 1.5.4]] - 21 May 2006&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.4==&lt;br /&gt;
*Moodle 1.4 - 31 August 2004&lt;br /&gt;
*Moodle 1.4.1 - 12 September 2004&lt;br /&gt;
*Moodle 1.4.2 - 5 November 2004&lt;br /&gt;
*Moodle 1.4.3 - 21 December 2004&lt;br /&gt;
*Moodle 1.4.4 - 7 March 2005 &lt;br /&gt;
*[[Moodle 1.4.5 release notes|Moodle 1.4.5]] - 7 May 2005&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.3==&lt;br /&gt;
*Moodle 1.3 - 25 May 2004&lt;br /&gt;
*Moodle 1.3.1 - 4 June 2004&lt;br /&gt;
*Moodle 1.3.2 - 9 July 2004&lt;br /&gt;
*Moodle 1.3.3 - 16 July 2004&lt;br /&gt;
*Moodle 1.3.4 - 11 August 2004&lt;br /&gt;
*Moodle 1.3.5 - 9 September 2004&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.2==&lt;br /&gt;
*Moodle 1.2 - 20 March 2004&lt;br /&gt;
*Moodle 1.2.1 - 25 March 2004&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.1==&lt;br /&gt;
*Moodle 1.1 - 29 August 2003&lt;br /&gt;
*Moodle 1.1.1 - 11 September 2003&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==Moodle 1.0==&lt;br /&gt;
*Moodle 1.0 - 20 August 2002&lt;br /&gt;
*Moodle 1.0.1 - 26 August 2002&lt;br /&gt;
*Moodle 1.0.2 - 2 September 2002&lt;br /&gt;
*Moodle 1.0.3 - 5 September 2002&lt;br /&gt;
*Moodle 1.0.4 - 10 September 2002&lt;br /&gt;
*Moodle 1.0.5 - 27 September 2002&lt;br /&gt;
*Moodle 1.0.6 - 26 October 2002&lt;br /&gt;
:: 1.0.6.1 - 6 November 2002&lt;br /&gt;
:: 1.0.6.2 - 11 November 2002&lt;br /&gt;
:: 1.0.6.3 - 14 November 2002&lt;br /&gt;
:: 1.0.6.4 - 25 November 2002&lt;br /&gt;
*Moodle 1.0.7 - 9 December 2002&lt;br /&gt;
*Moodle 1.0.8 - 7 January 2003&lt;br /&gt;
*Moodle 1.0.9 - 30 May 2003&lt;br /&gt;
* Support has ended&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Roadmap]] - future versions&lt;br /&gt;
*[[Moodle versions]] - an explanation of how our versions work plus version numbers for each release (for $plugin-&amp;gt;requires)&lt;br /&gt;
&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Core development]]&lt;br /&gt;
&lt;br /&gt;
[[fr:Historique des versions]]&lt;br /&gt;
[[es:dev/Historia de las versiones]]&lt;br /&gt;
[[de:Versionshistorie]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.6_release_notes&amp;diff=55008</id>
		<title>Moodle 3.6 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.6_release_notes&amp;diff=55008"/>
		<updated>2018-11-15T15:36:30Z</updated>

		<summary type="html">&lt;p&gt;Fox: Database versions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: Not yet released - scheduled for 26 November 2018&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.6%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.6].&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from a previous version, please see [[:en:Upgrading|Upgrading]] in the user docs. &#039;&#039;In particular, for sites using a custom theme or login form, from 3.6 onwards, the login form must include a new login token field. See [[Login token]] for details.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.1 or later&lt;br /&gt;
* PHP version: minimum PHP 7.0.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.3&#039;&#039;. PHP 7.1.x and 7.2.x are supported too. PHP 7.x could have some [https://docs.moodle.org/dev/Moodle_and_PHP7#Can_I_use_PHP7_yet.3F engine limitations]. &lt;br /&gt;
* PHP extension &#039;&#039;&#039;intl&#039;&#039;&#039; is required since Moodle 3.4 (it was recommended in 2.0 onwards) &lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.4&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.6&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2008&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 11.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://whatbrowser.org&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle 3.5:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other Highlights==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
===For developers===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.5 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.6]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.6]]&lt;br /&gt;
[[es:Notas de Moodle 3.6]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Implementing_Reset_course_functionality_in_a_module&amp;diff=54964</id>
		<title>Implementing Reset course functionality in a module</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Implementing_Reset_course_functionality_in_a_module&amp;diff=54964"/>
		<updated>2018-11-08T10:19:16Z</updated>

		<summary type="html">&lt;p&gt;Fox: Typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The course reset code is triggered from /course/reset.php. To have your module included, you need to implement the three functions described below. To work out how to do this, a good example is to look at the implementations in /mod/forum/lib.php&lt;br /&gt;
&lt;br /&gt;
==&#039;&#039;mymodule&#039;&#039;_reset_course_form_definition(&amp;amp;$mform)==&lt;br /&gt;
&lt;br /&gt;
This is called directly by /course/reset.php. It needs to output some form controls to control different options for resetting your module. You should use Form API for create form.&lt;br /&gt;
&lt;br /&gt;
The convention is to call settings relating your your module reset_&#039;&#039;mymodule&#039;&#039;_&#039;&#039;something&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The forum implementation is a good model:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Called by course/reset.php&lt;br /&gt;
 */&lt;br /&gt;
function forum_reset_course_form_definition(&amp;amp;$mform) {&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;header&#039;, &#039;forumheader&#039;, get_string(&#039;modulenameplural&#039;, &#039;forum&#039;));&lt;br /&gt;
&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;reset_forum_all&#039;, get_string(&#039;resetforumsall&#039;,&#039;forum&#039;));&lt;br /&gt;
&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;select&#039;, &#039;reset_forum_types&#039;, get_string(&#039;resetforums&#039;, &#039;forum&#039;), forum_get_forum_types_all(), array(&#039;multiple&#039; =&amp;gt; &#039;multiple&#039;));&lt;br /&gt;
    $mform-&amp;gt;setAdvanced(&#039;reset_forum_types&#039;);&lt;br /&gt;
    $mform-&amp;gt;disabledIf(&#039;reset_forum_types&#039;, &#039;reset_forum_all&#039;, &#039;checked&#039;);&lt;br /&gt;
&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;reset_forum_subscriptions&#039;, get_string(&#039;resetsubscriptions&#039;,&#039;forum&#039;));&lt;br /&gt;
    $mform-&amp;gt;setAdvanced(&#039;reset_forum_subscriptions&#039;);&lt;br /&gt;
&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;reset_forum_track_prefs&#039;, get_string(&#039;resettrackprefs&#039;,&#039;forum&#039;));&lt;br /&gt;
    $mform-&amp;gt;setAdvanced(&#039;reset_forum_track_prefs&#039;);&lt;br /&gt;
    $mform-&amp;gt;disabledIf(&#039;reset_forum_track_prefs&#039;, &#039;reset_forum_all&#039;, &#039;checked&#039;);&lt;br /&gt;
&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;reset_forum_ratings&#039;, get_string(&#039;deleteallratings&#039;));&lt;br /&gt;
    $mform-&amp;gt;disabledIf(&#039;reset_forum_ratings&#039;, &#039;reset_forum_all&#039;, &#039;checked&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&#039;&#039;mymodule&#039;&#039;_reset_userdata($data)==&lt;br /&gt;
 &lt;br /&gt;
This actually does the resetting. It is called indirectly, /course/reset.php calls reset_course_userdata() in /lib/moodlelib.php, which then calls the functions for each module.&lt;br /&gt;
&lt;br /&gt;
The $data parameter is what came back from the form printed by forum_reset_course. In particular, $data-&amp;gt;courseid is the id of the course we are cleaning up.&lt;br /&gt;
&lt;br /&gt;
The forum implementation is again a good one to study, here is a very simple example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
function example_reset_userdata($data) {&lt;br /&gt;
    if (!empty($data-&amp;gt;reset_example_frogs)) {&lt;br /&gt;
        if (delete_records(&#039;example_frogs&#039;, &#039;couresid&#039;, $data-&amp;gt;courseid) and $showfeedback) {&lt;br /&gt;
            notify(get_string(&#039;frogsdeleted&#039;, &#039;example&#039;), &#039;notifysuccess&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
    if (!empty($data-&amp;gt;reset_example_newts)) {&lt;br /&gt;
        if (delete_records(&#039;example_newts&#039;, &#039;couresid&#039;, $data-&amp;gt;courseid) and $showfeedback) {&lt;br /&gt;
            notify(get_string(&#039;newtsdeleted&#039;, &#039;example&#039;), &#039;notifysuccess&#039;);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==&#039;&#039;mymodule&#039;&#039;_reset_course_form_defaults($course)==&lt;br /&gt;
&lt;br /&gt;
Used for set default values to form&#039;s elements displayed by &#039;&#039;mymodule&#039;&#039;_reset_course_form_definition. The forum implementation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&amp;lt;nowiki&amp;gt;&lt;br /&gt;
function forum_reset_course_form_defaults($course) {&lt;br /&gt;
    return array(&#039;reset_forum_all&#039;=&amp;gt;1, &#039;reset_forum_subscriptions&#039;=&amp;gt;0, &#039;reset_forum_track_prefs&#039;=&amp;gt;0, &#039;reset_forum_ratings&#039;=&amp;gt;1);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/nowiki&amp;gt;&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[ja:開発:コースのリセット機能をモジュールに実装する]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_App_Plugins_Development_Guide&amp;diff=54381</id>
		<title>Moodle App Plugins Development Guide</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_App_Plugins_Development_Guide&amp;diff=54381"/>
		<updated>2018-06-12T14:49:35Z</updated>

		<summary type="html">&lt;p&gt;Fox: /* New approach */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle Mobile}}&lt;br /&gt;
&lt;br /&gt;
==Context==&lt;br /&gt;
Since Moodle 3.1 it is possible to support different types of Moodle plugins in the Mobile app via the [[Moodle Mobile Remote add-ons|Remote add-ons]] functionality.&lt;br /&gt;
&lt;br /&gt;
Remote add-ons allow a developer to add complete support to their plugins in the Mobile app, but they have some disadvantages:&lt;br /&gt;
* Remote add-ons are not easy to develop and test since they are required to be developed as an Angular JS/Ionic module.&lt;br /&gt;
* A zip file containing the plugin must be downloaded from the server to be lazy-loaded.&lt;br /&gt;
* It is not easy to maintain or upgrade them.&lt;br /&gt;
* Developers had to set up a local Mobile development environment&lt;br /&gt;
&lt;br /&gt;
In order to allow plugin developers to make their plugins compatible with the app, the Mobile team has been thinking in a new way to extend the mobile app features following these premises:&lt;br /&gt;
* It has to be easy to develop&lt;br /&gt;
* It should work without developing Angular/Ionic code&lt;br /&gt;
* It has to be easy to maintain&lt;br /&gt;
* It has to be supported since Moodle 3.1 at least&lt;br /&gt;
* Should support all the different types of Moodle plugins supported by the app&lt;br /&gt;
* Should work in any type of device&lt;br /&gt;
* Should not require JavaScript at all, although in some cases it will be needed. In the latter case, we’ll try to simplify the required JavaScript&lt;br /&gt;
&lt;br /&gt;
==New approach==&lt;br /&gt;
&lt;br /&gt;
We published an initial draft specification, and last month we started its implementation. During the implementation process we decided to make the following changes to the initial plans in order to make developers life easier:&lt;br /&gt;
&lt;br /&gt;
* There will be just one way to support plugins in the app.&lt;br /&gt;
* This new way will allow developers to support plugins using PHP code, templates and Ionic markup (html components).&lt;br /&gt;
* The use of JavaScript will be optional (but some type of advanced plugins may require it)&lt;br /&gt;
* Developers won’t need to set up a Mobile development environment, they will be able to test using the latest version of the official app (although setting up a local Mobile environment is recommended for complex plugins).&lt;br /&gt;
&lt;br /&gt;
This means that remote add-ons won’t be necessary anymore, and developers won’t have to learn Ionic 3 / Angular and set up a new mobile development environment to migrate them.&lt;br /&gt;
&lt;br /&gt;
Important notes:&lt;br /&gt;
* Moodle Mobile 3.5 (to be released June 2018) will be the first version of the Mobile app supporting this new type of plugins.&lt;br /&gt;
* Remote add-ons will have to be migrated to the new simpler way (following this documentation)&lt;br /&gt;
* These features are natively supported in Moodle 3.5, but for previous versions you will need to install the Moodle Mobile Additional Features plugin.&lt;br /&gt;
&lt;br /&gt;
==How it works==&lt;br /&gt;
&lt;br /&gt;
The overall idea is to allow Moodle plugins to extend different areas in the app with &#039;&#039;just PHP server side&#039;&#039; code and Ionic 3 markup (custom html elements that are called components) using a set of custom Ionic directives and components.&lt;br /&gt;
&lt;br /&gt;
Developers will have to:&lt;br /&gt;
# Create a db/mobile.php file in their plugins. In this file developers will be able to indicate which areas of the app they want to extend, for example, adding a new option in the main menu, implementing an activity module not supported, including a new option in the course menu, including a new option in the user profile, etc. All the areas supported are described further in this document.&lt;br /&gt;
# Create new functions in a reserved namespace that will return the content of the new options. The content should be returned rendered (html). The template should use [https://ionicframework.com/docs/components/ Ionic components] so that it looks native (custom html elements) but it can be generated using mustache templates. &lt;br /&gt;
&lt;br /&gt;
Let’s clarify some points:&lt;br /&gt;
&lt;br /&gt;
* You don’t need to create new Web Service functions (although you will be able to use them for advanced features). You just need plain php functions that will be placed in a reserved namespace.&lt;br /&gt;
* Those functions will be exported via the Web Service function tool_mobile_get_content&lt;br /&gt;
* As arguments of your functions you will always receive the userid, some relevant details of the app (app version, current language in the app, etc…) and some specific data depending on the type of plugin (courseid, cmid, …).&lt;br /&gt;
* We provide a list of custom Ionic components and directives (html tags) that will provide dynamic behaviour, like indicating that you are linking a file that can be downloaded, or to allow a transition to new pages into the app calling a specific function in the server, submit form data to the server  etc..&lt;br /&gt;
&lt;br /&gt;
==Step by step example==&lt;br /&gt;
&lt;br /&gt;
In this example, we are going to update an existing plugin ([https://github.com/markn86/moodle-mod_certificate Certificate activity module]) that currently uses a Remote add-on.&lt;br /&gt;
This is a simple activity module that displays the certificate issued for the current user along with the list of the dates of previously issued certificates. It also stores in the course log that the user viewed a certificate. This module also works offline: when the user downloads the course or activity, the data is pre-fetched and can be viewed offline.&lt;br /&gt;
&lt;br /&gt;
The example code can be downloaded from here (see last commit) https://github.com/jleyva/moodle-mod_certificate/commits/MOBILE-2363&lt;br /&gt;
&lt;br /&gt;
===Step 1. Update the db/mobile.php file===&lt;br /&gt;
In this case, we are updating an existing file but for new plugins, you should create this new file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$addons = array(&lt;br /&gt;
    &amp;quot;mod_certificate&amp;quot; =&amp;gt; array( // Plugin identifier&lt;br /&gt;
    	&#039;handlers&#039; =&amp;gt; array( // Different places where the plugin will display content.&lt;br /&gt;
            &#039;coursecertificate&#039; =&amp;gt; array( // Handler unique name (alphanumeric).&lt;br /&gt;
            	&#039;displaydata&#039; =&amp;gt; array(&lt;br /&gt;
                	&#039;icon&#039; =&amp;gt; $CFG-&amp;gt;wwwroot . &#039;/mod/certificate/pix/icon.gif&#039;,&lt;br /&gt;
                	&#039;class&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
            	),&lt;br /&gt;
       &lt;br /&gt;
            	&#039;delegate&#039; =&amp;gt; &#039;CoreCourseModuleDelegate&#039;, // Delegate (where to display the link to the plugin)&lt;br /&gt;
            	&#039;method&#039; =&amp;gt; &#039;mobile_course_view&#039;, // Main function in \mod_certificate\output\mobile&lt;br /&gt;
            	&#039;offlinefunctions&#039; =&amp;gt; array(&lt;br /&gt;
                    &#039;mobile_course_view&#039; =&amp;gt; array(),&lt;br /&gt;
                    &#039;mobile_issues_view&#039; =&amp;gt; array()&lt;br /&gt;
                 )       // Function that needs to be downloaded for offline.&lt;br /&gt;
            )&lt;br /&gt;
    	),&lt;br /&gt;
	&#039;lang&#039; =&amp;gt; array(	// Language strings that are used in all the handlers.&lt;br /&gt;
                array(&#039;pluginname&#039;, &#039;certificate),&lt;br /&gt;
                array(&#039;summaryofattempts&#039;, &#039;certificate),&lt;br /&gt;
                array(&#039;getcertificate&#039;, &#039;certificate),&lt;br /&gt;
                array(&#039;requiredtimenotmet&#039;, &#039;certificate),&lt;br /&gt;
		 array(&#039;viewcertificateviews&#039;, &#039;certificate&#039;)&lt;br /&gt;
        ),&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
;Plugin identifier:&lt;br /&gt;
: A unique name for the plugin, it can be anything (there’s no need to match the module name).&lt;br /&gt;
 &lt;br /&gt;
;Handlers  (Different places where the plugin will display content):&lt;br /&gt;
: A plugin can be displayed in different views in the app. Each view should have a unique name inside the plugin scope (alphanumeric).&lt;br /&gt;
&lt;br /&gt;
; Display data:&lt;br /&gt;
: This is only needed for certain types of plugins. Also, depending on the type of delegate it may require additional (or less fields), in this case we are indicating the module icon.&lt;br /&gt;
	&lt;br /&gt;
; Delegate&lt;br /&gt;
: Where to display the link to the plugin, see the Delegates chapter in this documentation for all the possible options.&lt;br /&gt;
&lt;br /&gt;
; Method:&lt;br /&gt;
: This is the function in the Moodle component/lib.php file to be executed the first time the user clicks in the new option displayed in the app. The function should be a method of a Mobile class under the output/mobile namespace.	&lt;br /&gt;
&lt;br /&gt;
; Offlinefunctions&lt;br /&gt;
: These are the functions that need to be downloaded for offline usage. This is the list of functions that need to be called and stored when the user downloads a course for offline usage. Please note that you can add functions here that are not even listed in the mobile.php file. &lt;br /&gt;
: In our example, downloading for offline access will mean that we&#039;ll execute the functions for getting the certificate and issued certificates passing as parameters the current userid (and courseid when we are using the mod or course delegate). If we have the result of those functions stored in the app, we&#039;ll be able to display the certificate information even if the user is offline.&lt;br /&gt;
: Offline functions will be mostly used to display information for final users, any further interaction with the view won’t be supported offline (for example, trying to send information when the user is offline).&lt;br /&gt;
: You can indicate here other Web Services functions, indicating the parameters that they might need from a defined subset (currently userid and courseid)&lt;br /&gt;
: Prefetching the module will also download all the files returned by the methods in these offline functions (in the &#039;&#039;files&#039;&#039; array).&lt;br /&gt;
&lt;br /&gt;
;Lang:&lt;br /&gt;
: The language pack string ids used in the plugin by all the handlers. Please note that you should avoid adding all the plugin string ids (including those unused) because the Web Service that returns the plugin information will include the translation of each string id for every language installed in the platform.&lt;br /&gt;
&lt;br /&gt;
There are additional attributes supported by the mobile.php list, see “Mobile.php supported options” section below.&lt;br /&gt;
&lt;br /&gt;
===Step 2. Creating the main function===&lt;br /&gt;
&lt;br /&gt;
The main function displays the current issued certificate (or several warnings if it’s not possible to issue a certificate). It also displays a link to view the dates of previously issued certificates.&lt;br /&gt;
&lt;br /&gt;
All the functions must be created in the plugin or subsystem classes/output directory, the name of the class must be mobile.&lt;br /&gt;
&lt;br /&gt;
For this example (mod_certificate plugin) the namespace name will be mod_certificate\output.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/classes/output/mobile.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
namespace mod_certificate\output;&lt;br /&gt;
&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
&lt;br /&gt;
use context_module;&lt;br /&gt;
use mod_certificate_external;&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Mobile output class for certificate&lt;br /&gt;
 *&lt;br /&gt;
 * @package	mod_certificate&lt;br /&gt;
 * @copyright  2018 Juan Leyva&lt;br /&gt;
 * @license	http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
class mobile {&lt;br /&gt;
&lt;br /&gt;
	/**&lt;br /&gt;
 	* Returns the certificate course view for the mobile app.&lt;br /&gt;
 	* @param  array $args Arguments from tool_mobile_get_content WS&lt;br /&gt;
 	*&lt;br /&gt;
 	* @return array   	HTML, javascript and otherdata&lt;br /&gt;
 	*/&lt;br /&gt;
    public static function mobile_course_view($args) {&lt;br /&gt;
    	global $OUTPUT, $USER, $DB;&lt;br /&gt;
&lt;br /&gt;
    	$args = (object) $args;&lt;br /&gt;
    	$cm = get_coursemodule_from_id(&#039;certificate&#039;, $args-&amp;gt;cmid);&lt;br /&gt;
&lt;br /&gt;
    	// Capabilities check.&lt;br /&gt;
    	require_login($args-&amp;gt;courseid , false , $cm, true, true);&lt;br /&gt;
&lt;br /&gt;
    	$context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    	require_capability (&#039;mod/certificate:view&#039;, $context);&lt;br /&gt;
    	if ($args-&amp;gt;userid != $USER-&amp;gt;id) {&lt;br /&gt;
        	require_capability(&#039;mod/certificate:manage&#039;, $context);&lt;br /&gt;
    	}&lt;br /&gt;
    	$certificate = $DB-&amp;gt;get_record(&#039;certificate&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;instance));&lt;br /&gt;
&lt;br /&gt;
    	// Get certificates from external (taking care of exceptions).&lt;br /&gt;
    	try {&lt;br /&gt;
        	$issued = mod_certificate_external::issue_certificate($cm-&amp;gt;instance);&lt;br /&gt;
        	$certificates = mod_certificate_external::get_issued_certificates($cm-&amp;gt;instance);&lt;br /&gt;
        	$issues = array_values($certificates[&#039;issues&#039;]); // Make it mustache compatible.&lt;br /&gt;
    	} catch (Exception $e) {&lt;br /&gt;
        	$issues = array();&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	// Set timemodified for each certificate.&lt;br /&gt;
    	foreach ($issues as $issue) {&lt;br /&gt;
        	if (empty($issue-&amp;gt;timemodified)) {&lt;br /&gt;
            		$issue-&amp;gt;timemodified = $issue-&amp;gt;timecreated;&lt;br /&gt;
        	}&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	$showget = true;&lt;br /&gt;
    	if ($certificate-&amp;gt;requiredtime &amp;amp;&amp;amp; !has_capability(&#039;mod/certificate:manage&#039;, $context)) {&lt;br /&gt;
        	if (certificate_get_course_time($certificate-&amp;gt;course) &amp;lt; ($certificate-&amp;gt;requiredtime * 60)) {&lt;br /&gt;
            		$showget = false;&lt;br /&gt;
        	}&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	$certificate-&amp;gt;name = format_string($certificate-&amp;gt;name);&lt;br /&gt;
    	list($certificate-&amp;gt;intro, $certificate-&amp;gt;introformat) =&lt;br /&gt;
                    	external_format_text($certificate-&amp;gt;intro, $certificate-&amp;gt;introformat, $context-&amp;gt;id,&#039;mod_certificate&#039;, &#039;intro&#039;);&lt;br /&gt;
    	$data = array(&lt;br /&gt;
        	&#039;certificate&#039; =&amp;gt; $certificate,&lt;br /&gt;
        	&#039;showget&#039; =&amp;gt; $showget &amp;amp;&amp;amp; count($issues) &amp;gt; 0,&lt;br /&gt;
        	&#039;issues&#039; =&amp;gt; $issues,&lt;br /&gt;
        	&#039;issue&#039; =&amp;gt; $issues[0],&lt;br /&gt;
&#039;numissues&#039; =&amp;gt; count($issues),&lt;br /&gt;
        	&#039;cmid&#039; =&amp;gt; $cm-&amp;gt;id,&lt;br /&gt;
        	&#039;courseid&#039; =&amp;gt; $args-&amp;gt;courseid&lt;br /&gt;
    	);&lt;br /&gt;
&lt;br /&gt;
    	return array(&lt;br /&gt;
        	&#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
            	array(&lt;br /&gt;
                	&#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                	&#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
            	),&lt;br /&gt;
        	),&lt;br /&gt;
        	&#039;javascript&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        	&#039;otherdata&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        	&#039;files&#039; =&amp;gt; $issues&lt;br /&gt;
    	);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Let’s go through the function code to analyse the different parts.&lt;br /&gt;
&lt;br /&gt;
;Function declaration: &lt;br /&gt;
: The function name is the same as the one used in the mobile.php file (method field). There is only one argument “$args” which is an array containing all the information sent by the mobile app (the courseid, userid, appid, appversionname, appversioncode, applang, appcustomurlscheme…)&lt;br /&gt;
&lt;br /&gt;
; Function implementation:&lt;br /&gt;
: In the first part of the function, we check permissions and capabilities (like a view.php script would do normally). Then we retrieve the certificate information that’s necessary to display the template.&lt;br /&gt;
&lt;br /&gt;
Finally, we return:&lt;br /&gt;
* The rendered template (notice that we could return more than one template but we usually would only need one). By default the app will always render the first template received, the rest of the templates can be used if the plugin defines some Javascript code.&lt;br /&gt;
* JavaScript: Empty, because we don’t need any in this case&lt;br /&gt;
* Other data: Empty as well, because we don’t need any additional data to be used by directives or components in the template. This field will be published as an object supporting 2-way-data-bind to the template.&lt;br /&gt;
* Files: A list of files that the app should be able to download (for offline usage mostly)&lt;br /&gt;
&lt;br /&gt;
===Step 3. Creating the template for the main function===&lt;br /&gt;
&lt;br /&gt;
This is the most important part of your plugin because it contains the code that will be rendered on the mobile app.&lt;br /&gt;
&lt;br /&gt;
In this template we’ll be using Ionic and custom directives and components available in the Mobile app.&lt;br /&gt;
&lt;br /&gt;
All the HTML attributes starting with ion- are ionic components. Most of the time the component name is self-explanatory but you may refer to a detailed guide here: https://ionicframework.com/docs/components/ &lt;br /&gt;
&lt;br /&gt;
All the HTML attributes starting with &#039;&#039;core-&#039;&#039; are custom components of the Mobile app.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/templates/mobile_view_page.mustache&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
{{=&amp;lt;% %&amp;gt;=}}&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;core-course-module-description description=&amp;quot;&amp;lt;% certificate.intro %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-course-module-description&amp;gt;&lt;br /&gt;
&lt;br /&gt;
	&amp;lt;ion-list&amp;gt;&lt;br /&gt;
    	&amp;lt;ion-list-header&amp;gt;&lt;br /&gt;
        	&amp;lt;p class=&amp;quot;item-heading&amp;quot;&amp;gt;{{ &#039;plugin.mod_certificate.summaryofattempts&#039; | translate }}&amp;lt;/p&amp;gt;&lt;br /&gt;
    	&amp;lt;/ion-list-header&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;%#issues%&amp;gt;&lt;br /&gt;
        	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
            	&amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-new-content title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
                	{{ &#039;plugin.mod_certificate.viewcertificateviews&#039; | translate: {$a: &amp;lt;% numissues %&amp;gt;} }}&lt;br /&gt;
            	&amp;lt;/button&amp;gt;&lt;br /&gt;
        	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/issues%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;%#showget%&amp;gt;&lt;br /&gt;
    	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
        	&amp;lt;button ion-button block core-course-download-module-main-file moduleId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot; courseId=&amp;quot;&amp;lt;% certificate.course %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; [files]=&amp;quot;[{fileurl: &#039;&amp;lt;% issue.fileurl %&amp;gt;&#039;, filename: &#039;&amp;lt;% issue.filename %&amp;gt;&#039;, timemodified: &#039;&amp;lt;% issue.timemodified %&amp;gt;&#039;, mimetype: &#039;&amp;lt;% issue.mimetype %&amp;gt;&#039;}]&amp;quot;&amp;gt;&lt;br /&gt;
            	&amp;lt;ion-icon name=&amp;quot;cloud-download&amp;quot; item-start&amp;gt;&amp;lt;/ion-icon&amp;gt;&lt;br /&gt;
            	{{ &#039;plugin.mod_certificate.getcertificate&#039; | translate }}&lt;br /&gt;
        	&amp;lt;/button&amp;gt;&lt;br /&gt;
    	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/showget%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;%^showget%&amp;gt;&lt;br /&gt;
    	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
        	&amp;lt;p&amp;gt;{{ &#039;plugin.mod_certificate.requiredtimenotmet&#039; | translate }}&amp;lt;/p&amp;gt;&lt;br /&gt;
    	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/showget%&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    	&amp;lt;!-- Call log WS when the template is loaded. --&amp;gt;&lt;br /&gt;
    	&amp;lt;span core-site-plugins-call-ws-on-load name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
	&amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the first line of the template we switch delimiters to avoid conflicting with Ionic delimiters (that are curly brackets like mustache). &lt;br /&gt;
&lt;br /&gt;
Then we display the module description using &amp;lt;code&amp;gt;&amp;lt;core-course-module-description&amp;lt;/code&amp;gt; that is a component used to include the course module description.&lt;br /&gt;
&lt;br /&gt;
For displaying the certificate information we create a list of elements, adding a header on top.&lt;br /&gt;
The following line &amp;lt;code&amp;gt;{{ &#039;plugin.mod_certificate.summaryofattempts&#039; | translate }}&amp;lt;/code&amp;gt; indicates that the Mobile app will translate the &#039;&#039;summaryofattempts&#039;&#039; string id (here we could’ve used mustache translation but it is usually better to delegate the strings translations to the app). The string id has this format: &lt;br /&gt;
&lt;br /&gt;
“plugin” + plugin identifier (from mobile.php) +  string id (the string must be indicated in the lang field in mobile.php). &lt;br /&gt;
&lt;br /&gt;
Then we display a button to transition to another page if there are certificates issued. The attribute (directive) &amp;lt;code&amp;gt;core-site-plugins-new-content&amp;lt;/code&amp;gt; indicates that if the user clicks the button, we need to call the function “mobile_issues_view” in the component “mod_certificate” passing as arguments the cmid and courseid. The content returned by this function will be displayed in a new page (see Step 4 for the code of this new page).&lt;br /&gt;
&lt;br /&gt;
Just after this button we display another one but this time for downloading an issued certificate. The &amp;lt;code&amp;gt;core-course-download-module-main-file&amp;lt;/code&amp;gt; directive indicates that clicking this button is for downloading the whole activity and opening the main file. This means that, when the user clicks this button, the whole certificate activity will be available in offline.&lt;br /&gt;
&lt;br /&gt;
Finally, just before the ion-list is closed, we use the &amp;lt;code&amp;gt;core-site-plugins-call-ws-on-load&amp;lt;/code&amp;gt; directive to indicate that once the page is loaded, we need to call to a Web Service function in the server, in this case we are calling the &#039;&#039;mod_certificate_view_certificate&#039;&#039; that will log that the user viewed this page.&lt;br /&gt;
&lt;br /&gt;
As you can see, no JavaScript was necessary at all. We used plain HTML elements and attributes that did all the complex dynamic logic (like calling a Web Service) behind the scenes.&lt;br /&gt;
&lt;br /&gt;
===Step 4. Adding an additional page===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Partial file contents: mod/certificate/classes/output/mobile.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
     * Returns the certificate issues view for the mobile app.&lt;br /&gt;
     * @param  array $args Arguments from tool_mobile_get_content WS&lt;br /&gt;
     *&lt;br /&gt;
     * @return array   	HTML, javascript and otherdata&lt;br /&gt;
     */&lt;br /&gt;
    public static function mobile_issues_view($args) {&lt;br /&gt;
    	global $OUTPUT, $USER, $DB;&lt;br /&gt;
&lt;br /&gt;
    	$args = (object) $args;&lt;br /&gt;
    	$cm = get_coursemodule_from_id(&#039;certificate&#039;, $args-&amp;gt;cmid);&lt;br /&gt;
&lt;br /&gt;
    	// Capabilities check.&lt;br /&gt;
    	require_login($args-&amp;gt;courseid , false , $cm, true, true);&lt;br /&gt;
&lt;br /&gt;
    	$context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    	require_capability (&#039;mod/certificate:view&#039;, $context);&lt;br /&gt;
    	if ($args-&amp;gt;userid != $USER-&amp;gt;id) {&lt;br /&gt;
        	require_capability(&#039;mod/certificate:manage&#039;, $context);&lt;br /&gt;
    	}&lt;br /&gt;
    	$certificate = $DB-&amp;gt;get_record(&#039;certificate&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;instance));&lt;br /&gt;
&lt;br /&gt;
    	// Get certificates from external (taking care of exceptions).&lt;br /&gt;
    	try {&lt;br /&gt;
        	$issued = mod_certificate_external::issue_certificate($cm-&amp;gt;instance);&lt;br /&gt;
        	$certificates = mod_certificate_external::get_issued_certificates($cm-&amp;gt;instance);&lt;br /&gt;
        	$issues = array_values($certificates[&#039;issues&#039;]); // Make it mustache compatible.&lt;br /&gt;
    	} catch (Exception $e) {&lt;br /&gt;
        	$issues = array();&lt;br /&gt;
    	}&lt;br /&gt;
&lt;br /&gt;
    	$data = array(&lt;br /&gt;
        	&#039;issues&#039; =&amp;gt; $issues&lt;br /&gt;
    	);&lt;br /&gt;
&lt;br /&gt;
    	return array(&lt;br /&gt;
        	&#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
            	array(&lt;br /&gt;
                	&#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                	&#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_issues&#039;, $data),&lt;br /&gt;
            	),&lt;br /&gt;
        	),&lt;br /&gt;
        	&#039;javascript&#039; =&amp;gt; &#039;&#039;,&lt;br /&gt;
        	&#039;otherdata&#039; =&amp;gt; &#039;&#039;&lt;br /&gt;
    	);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function for the new page was added just after the mobile_course_view function, the code is quite similar: Capabilities checks, retrieves the information required for the template and returns the template rendered.&lt;br /&gt;
&lt;br /&gt;
The code of the mustache template is also very simple:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;File contents: mod/certificate/templates/mobile_view_issues.mustache&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
{{=&amp;lt;% %&amp;gt;=}}&lt;br /&gt;
&amp;lt;div&amp;gt;&lt;br /&gt;
	&amp;lt;ion-list&amp;gt;&lt;br /&gt;
    	&amp;lt;%#issues%&amp;gt;&lt;br /&gt;
        	&amp;lt;ion-item&amp;gt;&lt;br /&gt;
            	&amp;lt;p class=&amp;quot;item-heading&amp;quot;&amp;gt;{{ &amp;lt;%timecreated%&amp;gt; | coreToLocaleString }}&amp;lt;/p&amp;gt;&lt;br /&gt;
            	&amp;lt;p&amp;gt;&amp;lt;%grade%&amp;gt;&amp;lt;/p&amp;gt;&lt;br /&gt;
        	&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
    	&amp;lt;%/issues%&amp;gt;&lt;br /&gt;
	&amp;lt;/ion-list&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As we did in the previous template, in the first line of the template we switch delimiters to avoid conflicting with Ionic delimiters (that are curly brackets like mustache). &lt;br /&gt;
&lt;br /&gt;
Here we are creating an ionic list that will display a new item in the list per each issued certificated.&lt;br /&gt;
&lt;br /&gt;
For the issued certificated we’ll display the time when it was created (using the app filter &#039;&#039;coreToLocaleString&#039;&#039;). We are also displaying the grade displayed in the certificate (if any). &lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
The first and most important thing to know is that you don’t need a local mobile environment, you can just use the Chrome or Chromium browser to add mobile support to your plugins!&lt;br /&gt;
&lt;br /&gt;
Open this URL (with Chrome or Chromium browser): https://mobileapp.moodledemo.net/ and you will see a web version of the mobile app completely functional (except for some native features). This URL is updated with the latest integration version of the app.&lt;br /&gt;
&lt;br /&gt;
Please test that your site works correctly in the web version before starting any development.&lt;br /&gt;
&lt;br /&gt;
===Moodle version requirements===&lt;br /&gt;
&lt;br /&gt;
If your Moodle version is lower than 3.5 (to be released in May) you will need to install the [https://docs.moodle.org/en/Moodle_Mobile_additional_features Moodle Mobile additional features plugin]. &lt;br /&gt;
&lt;br /&gt;
Please use this development version for now: https://github.com/moodlehq/moodle-local_mobile/commits/MOODLE_31_STABLE (if your Moodle version is 3.2, 3.3 or 3.4) you will have to use the specific branch for your version but applying manually the [https://github.com/moodlehq/moodle-local_mobile/commits/MOODLE_31_STABLE last commit from the 3.1 branch] (the one with number MOBILE-2362).&lt;br /&gt;
&lt;br /&gt;
Also, when installing the Moodle Mobile Additional features plugin you must follow the installation instructions so the service is set up properly.&lt;br /&gt;
&lt;br /&gt;
Remember to update your plugin documentation to reflect that this plugin is mandatory for Mobile support. We don’t recommend to indicate in your plugin version.php a dependency to local_mobile though.&lt;br /&gt;
&lt;br /&gt;
===Development workflow===&lt;br /&gt;
&lt;br /&gt;
First of all, we recommend creating a simple &#039;&#039;mobile.php&#039;&#039; for displaying a new main menu option (even if your plugin won’t be in the main menu, just to verify that you are able to extend the app plugins). Then open the webapp (https://mobileapp.moodledemo.net/) or refresh the browser if it was already open. Check that you can correctly  see the new menu option you included.&lt;br /&gt;
&lt;br /&gt;
Then, develop the main function of the app returning a “Hello world” or basic code (without using templates) to see that everything works together. After adding the classes/output/mobile.php file it is very important to “Purge all caches” to avoid problems with the auto-loading cache.&lt;br /&gt;
&lt;br /&gt;
It is important to remember that:&lt;br /&gt;
* Any change in the mobile.php file will require you to refresh the web app page in the browser (remember to disable the cache in the Chrome developer options).&lt;br /&gt;
* Any change in an existing template or function won’t require to refresh the browser page. In most cases you should just do a PTR (Pull down To Refresh) in the page that displays the view returned by the function. Be aware that PTR will work only when using the “device” emulation in the browser (see following section).&lt;br /&gt;
&lt;br /&gt;
===Testing and debugging===&lt;br /&gt;
&lt;br /&gt;
To learn how to debug with the web version of the app, please read the following documents:&lt;br /&gt;
* [[Moodle Mobile debugging WS requests]] AND&lt;br /&gt;
* [[Moodle Mobile development using Chrome or Chromium]] (please, omit the installation section)&lt;br /&gt;
&lt;br /&gt;
For plugins using the Javascript API you may develop making use of the console.log function to add trace messages in your code that will be displayed in the browser console.&lt;br /&gt;
&lt;br /&gt;
==Mobile.php supported options==&lt;br /&gt;
&lt;br /&gt;
In the Step by Step section we learned about some of the existing options for handlers configuration. This is the full list of supported options:&lt;br /&gt;
&lt;br /&gt;
===Common options===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;displaydata&#039;&#039;&#039; (mandatory for certain types): Data used to display the handler. It will vary depending on the delegate, and some delegates won’t need it at all (like course format). Attributes usually required in the &#039;&#039;displaydata&#039;&#039;: title, icon, class.&lt;br /&gt;
* &#039;&#039;&#039;delegate&#039;&#039;&#039; (mandatory): Name of the delegate to register the handler in.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (mandatory): The function to call to retrieve the main page content.&lt;br /&gt;
* &#039;&#039;&#039;priority&#039;&#039;&#039; (optional): Priority of the handler. Only for certain delegates. Higher priority is displayed first. &lt;br /&gt;
* &#039;&#039;&#039;lang&#039;&#039;&#039; (optional): List of language strings.&lt;br /&gt;
* &#039;&#039;&#039;init&#039;&#039;&#039; (optional): A function to call to retrieve the initialization JS and the &amp;quot;restrict&amp;quot; to apply to the whole handler. It can also return templates that can be used from the Javascript of the init method or the Javascript of the handler’s method.&lt;br /&gt;
* &#039;&#039;&#039;restricttocurrentuser&#039;&#039;&#039; (optional) Only used if the delegate has a isEnabledForUser function. If true, the handler will only be shown for current user. For more info about displaying the plugin only for certain users, please see [[Mobile_support_for_plugins#Display_the_plugin_only_if_certain_conditions_are_met|Display the plugin only if certain conditions are met]].&lt;br /&gt;
* &#039;&#039;&#039;restricttoenrolledcourses&#039;&#039;&#039; (optional): Only used if the delegate has a isEnabledForCourse function. If true or not defined, the handler will only be shown for courses the user is enrolled in. For more info about displaying the plugin only for certain courses, please see [[Mobile_support_for_plugins#Display_the_plugin_only_if_certain_conditions_are_met|Display the plugin only if certain conditions are met]].&lt;br /&gt;
* &#039;&#039;&#039;styles&#039;&#039;&#039; (optional): An array with two properties: &#039;&#039;url&#039;&#039; and &#039;&#039;version&#039;&#039;. The URL should point to a CSS file, either using an absolute URL or a relative URL. This file will be downloaded and applied by the app. It&#039;s recommended to include styles that will only affect your plugin templates. The version number is used to determine if the file needs to be downloaded again, you should change the version number everytime you change the CSS file.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreCourseModuleDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;offlinefunctions&#039;&#039;&#039;: (optional) List of functions to call when prefetching the module. It can be a get_content method or a WS. You can filter the params received by the WS. By default, WS will receive these params: courseid, cmid, userid. Other valid values that will be added if they are present in the list of params: courseids (it will receive a list with the courses the user is enrolled in), component + &#039;id&#039; (e.g. certificateid).&lt;br /&gt;
* &#039;&#039;&#039;downloadbutton&#039;&#039;&#039;: (optional) Whether to display download button in the module. If not defined, the button will be shown if there is any offlinefunction.&lt;br /&gt;
* &#039;&#039;&#039;isresource&#039;&#039;&#039;: (optional) Whether the module is a resource or an activity. Only used if there is any offlinefunction. If your module relies on the &amp;quot;contents&amp;quot; field, then it should be true.&lt;br /&gt;
* &#039;&#039;&#039;updatesnames&#039;&#039;&#039;: (optional) Only used if there is any offlinefunction. A Regular Expression to check if there&#039;s any update in the module. It will be compared to the result of &#039;&#039;core_course_check_updates&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreCourseFormatDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;canviewallsections&#039;&#039;&#039;: (optional) Whether the course format allows seeing all sections in a single page. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;displayenabledownload&#039;&#039;&#039;: (optional) Whether the option to enable section/module download should be displayed. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;displaysectionselector&#039;&#039;&#039;: (optional) Whether the default section selector should be displayed. Defaults to true.&lt;br /&gt;
&lt;br /&gt;
===Options only for CoreUserDelegate===&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;type&#039;&#039;&#039;: The type of the addon. Values accepted: &#039;newpage&#039; (default) or  &#039;communication&#039;. &lt;br /&gt;
&lt;br /&gt;
==Delegates==&lt;br /&gt;
&lt;br /&gt;
===CoreMainMenuDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add new items to the main menu (currently displayed at the bottom of the app). &lt;br /&gt;
&lt;br /&gt;
===CoreCourseOptionsDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add new options in a course (Participants or Grades are examples of this type of delegate).&lt;br /&gt;
&lt;br /&gt;
===CoreCourseModuleDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting activity modules or resources, please review the specific options for this delegate in the “Options only for CoreCourseModuleDelegate” section.&lt;br /&gt;
&lt;br /&gt;
===CoreUserDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate when you want to add additional options in the user profile page in the app. Options can be of different types (newpage, communication or action).&lt;br /&gt;
&lt;br /&gt;
===CoreCourseFormatDelegate===&lt;br /&gt;
&lt;br /&gt;
You must use this delegate for supporting course formats, please review the specific options for this delegate in the “Options only for CoreCourseFormatDelegate” section.&lt;br /&gt;
&lt;br /&gt;
===Other advanced delegates===&lt;br /&gt;
&lt;br /&gt;
This delegates require JavaScript to be supported. See [[Mobile_support_for_plugins#Initialization|Initialization]] for more information.&lt;br /&gt;
&lt;br /&gt;
* CoreContentLinksDelegate&lt;br /&gt;
* CoreUserProfileFieldDelegate&lt;br /&gt;
* CoreCourseModulePrefetchDelegate&lt;br /&gt;
* CoreFileUploaderDelegate&lt;br /&gt;
* CorePluginFileDelegate&lt;br /&gt;
&lt;br /&gt;
==Available components and directives==&lt;br /&gt;
&lt;br /&gt;
===Difference between component and directives===&lt;br /&gt;
&lt;br /&gt;
A component (represented as an HTML tag) is used to add custom elements to the app.&lt;br /&gt;
Example of components are: ion-list, ion-item, core-search-box&lt;br /&gt;
&lt;br /&gt;
A directive (represented as an HTML attribute) allows you to extend a piece of HTML with additional information or functionality.&lt;br /&gt;
Example of directives are: core-auto-focus, *ngIf, ng-repeat&lt;br /&gt;
&lt;br /&gt;
The Mobile app uses Angular, Ionic and custom components and directives, for a full reference of:&lt;br /&gt;
* Angular directives, please check: https://angular.io/api?type=directive&lt;br /&gt;
* Ionic components, please check: https://ionicframework.com/docs/&lt;br /&gt;
&lt;br /&gt;
===Custom core components and directives===&lt;br /&gt;
&lt;br /&gt;
These are some useful custom components and directives (only available in the mobile app). Please notice that this isn’t the full list of components and directives of the app, it’s just an extract of the most common ones.&lt;br /&gt;
&lt;br /&gt;
====core-format-text====&lt;br /&gt;
&lt;br /&gt;
This directive formats the text and adds some directives needed for the app to work as it should. For example, it treats all links and all the embedded media so they work fine in the app. If some content in your template includes links or embedded media, please use this directive.&lt;br /&gt;
&lt;br /&gt;
This directive automatically applies core-external-content and core-link to all the links and embedded media.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;text&#039;&#039;&#039; (string): The text to format.&lt;br /&gt;
* &#039;&#039;&#039;siteId&#039;&#039;&#039; (string): Optional. Site ID to use. If not defined, current site.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to use when downloading embedded files.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
* &#039;&#039;&#039;adaptImg&#039;&#039;&#039; (boolean): Optional. Whether to adapt images to screen width. Defaults to true.&lt;br /&gt;
* &#039;&#039;&#039;clean&#039;&#039;&#039; (boolean): Optional. Whether all the HTML tags should be removed. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;singleLine&#039;&#039;&#039; (boolean): Optional. Whether new lines should be removed (all text in single line). Only if clean=true. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;maxHeight&#039;&#039;&#039; (number): Optional. Max height in pixels to render the content box. It should be 50 at least to make sense. Using this parameter will force display: block to calculate height better. If you want to avoid this use class=&amp;quot;inline&amp;quot; at the same time to use display: inline-block.&lt;br /&gt;
* &#039;&#039;&#039;fullOnClick&#039;&#039;&#039; (boolean): Optional. Whether it should open a new page with the full contents on click. Only if maxHeight is set and the content has been collapsed. Defaults to false.&lt;br /&gt;
* &#039;&#039;&#039;fullTitle&#039;&#039;&#039; (string): Optional. Title to use in full view. Defaults to &amp;quot;Description&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-format-text text=&amp;quot;&amp;lt;% cm.description %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-format-text&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-link====&lt;br /&gt;
&lt;br /&gt;
Directive to handle a link. It performs several checks, like checking if the link needs to be opened in the app, and opens the link as it should (without overriding the app).&lt;br /&gt;
&lt;br /&gt;
This directive is automatically applied to all the links and media inside core-format-text.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;capture&#039;&#039;&#039; (boolean): Optional. Whether the link needs to be captured by the app (check if the link can be handled by the app instead of opening it in a browser).&lt;br /&gt;
* &#039;&#039;&#039;inApp&#039;&#039;&#039; (boolean): Optional. True to open in embedded browser, false to open in system browser.&lt;br /&gt;
* &#039;&#039;&#039;autoLogin&#039;&#039;&#039; (string): Optional. If the link should be open with auto-login. Accepts the following values:&lt;br /&gt;
** &amp;quot;yes&amp;quot; -&amp;gt; Always auto-login.&lt;br /&gt;
** &amp;quot;no&amp;quot; -&amp;gt; Never auto-login.&lt;br /&gt;
** &amp;quot;check&amp;quot; -&amp;gt; Auto-login only if it points to the current site. Default value.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;&amp;lt;% cm.url %&amp;gt;&amp;quot; core-link&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-external-content====&lt;br /&gt;
&lt;br /&gt;
Directive to handle links to files and embedded files. This directive should be used in any link to a file or any embedded file that you want to have available when the app is offline. &lt;br /&gt;
&lt;br /&gt;
If a file is downloaded, its URL will be replaced by the local file URL.&lt;br /&gt;
&lt;br /&gt;
This directive is automatically applied to all the links and media inside core-format-text.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;siteId&#039;&#039;&#039; (string): Optional. Site ID to use. If not defined, current site.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to use when downloading embedded files.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;img src=&amp;quot;&amp;lt;% event.iconurl %&amp;gt;&amp;quot; core-external-content component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% event.id %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-user-link====&lt;br /&gt;
&lt;br /&gt;
Directive to go to user profile on click. When the user clicks the element where this directive is attached, the right user profile will be opened.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;userId&#039;&#039;&#039; (number): User id to open the profile.&lt;br /&gt;
* &#039;&#039;&#039;courseId&#039;&#039;&#039; (number): Optional. Course id to show the user info related to that course.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;a ion-item core-user-link userId=&amp;quot;&amp;lt;% userid %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-file====&lt;br /&gt;
&lt;br /&gt;
Component to handle a remote file. It shows the file name, icon (depending on mimetype) and a button to download/refresh it. The user can identify if the file is downloaded or not based on the button.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* file (object): The file. Must have a property &#039;filename&#039; and a &#039;fileurl&#039; or &#039;url&#039;&lt;br /&gt;
* component (string): Optional. Component the file belongs to.&lt;br /&gt;
* componentId (string|number): Optional. ID to use in conjunction with the component.&lt;br /&gt;
* canDelete (boolean): Optional. Whether file can be deleted.&lt;br /&gt;
* alwaysDownload (boolean): Optional. Whether it should always display the refresh button when the file is downloaded. Use it for files that you cannot determine if they&#039;re outdated or not.&lt;br /&gt;
* canDownload (boolean): Optional. Whether file can be downloaded. Defaults to true.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-file [file]=&amp;quot;{fileurl: &amp;lt;% issue.url %&amp;gt;, filename: &amp;lt;% issue.name %&amp;gt;, timemodified: &amp;lt;% issue.timemodified %&amp;gt;, filesize: &amp;lt;% issue.size %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;/core-file&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-download-file====&lt;br /&gt;
&lt;br /&gt;
Directive to allow downloading and open a file. When the item with this directive is clicked, the file will be downloaded (if needed) and opened.&lt;br /&gt;
&lt;br /&gt;
It is usually recommended to use the core-file component since it also displays the state of the file.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;core-download-file&#039;&#039;&#039; (object): The file to download.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to link the file to.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. Component ID to use in conjunction with the component.&lt;br /&gt;
&lt;br /&gt;
Example usage: a button to download a file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button [core-download-file]=&amp;quot;{fileurl: &amp;lt;% issue.url %&amp;gt;, timemodified: &amp;lt;% issue.timemodified %&amp;gt;, filesize: &amp;lt;% issue.size %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; componentId=&amp;quot;&amp;lt;% cm.id %&amp;gt;&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.download | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-course-download-module-main-file====&lt;br /&gt;
&lt;br /&gt;
Directive to allow downloading and opening the main file of a module.&lt;br /&gt;
&lt;br /&gt;
When the item with this directive is clicked, the whole module will be downloaded (if needed) and its main file opened. This is meant for modules like mod_resource.&lt;br /&gt;
&lt;br /&gt;
This directive must receive either a module or a moduleId. If no files are provided, it will use module.contents.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;module&#039;&#039;&#039; (object): Optional. The module object. Required if module is not supplied.&lt;br /&gt;
* &#039;&#039;&#039;moduleId&#039;&#039;&#039; (number): Optional. The module ID. Required if module is not supplied.&lt;br /&gt;
* &#039;&#039;&#039;courseId&#039;&#039;&#039; (number): The course ID the module belongs to.&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): Optional. Component to link the file to.&lt;br /&gt;
* &#039;&#039;&#039;componentId&#039;&#039;&#039; (string|number): Optional. Component ID to use in conjunction with the component. If not defined, moduleId.&lt;br /&gt;
* &#039;&#039;&#039;files&#039;&#039;&#039; (object[]): Optional. List of files of the module. If not provided, use module.contents.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block core-course-download-module-main-file moduleId=&amp;quot;&amp;lt;% cmid %&amp;gt;&amp;quot; courseId=&amp;quot;&amp;lt;% certificate.course %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; [files]=&amp;quot;[{fileurl: &#039;&amp;lt;% issue.fileurl %&amp;gt;&#039;, filename: &#039;&amp;lt;% issue.filename %&amp;gt;&#039;, timemodified: &#039;&amp;lt;% issue.timemodified %&amp;gt;&#039;, mimetype: &#039;&amp;lt;% issue.mimetype %&amp;gt;&#039;}]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getcertificate&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-navbar-buttons====&lt;br /&gt;
&lt;br /&gt;
Component to add buttons to the app&#039;s header without having to place them inside the header itself. Using this component in a site plugin will allow adding buttons to the header of the current page.&lt;br /&gt;
&lt;br /&gt;
If this component indicates a position (start/end), the buttons will only be added if the header has some buttons in that position. If no start/end is specified, then the buttons will be added to the first &amp;lt;ion-buttons&amp;gt; found in the header.&lt;br /&gt;
&lt;br /&gt;
You can use the [hidden] input to hide all the inner buttons if a certain condition is met.&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;core-navbar-buttons end&amp;gt;&lt;br /&gt;
    &amp;lt;button ion-button icon-only (click)=&amp;quot;action()&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ion-icon name=&amp;quot;funnel&amp;quot;&amp;gt;&amp;lt;/ion-icon&amp;gt;&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/core-navbar-buttons&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Specific component and directives for plugins===&lt;br /&gt;
&lt;br /&gt;
These are component and directives created specifically for supporting Moodle plugins.&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-new-content====&lt;br /&gt;
&lt;br /&gt;
Directive to display a new content when clicked. This new content can be displayed in a new page or in the current page (only if the current page is already displaying a site plugin content).&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): The component of the new content.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (string): The method to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;args&#039;&#039;&#039; (object): The params to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;title&#039;&#039;&#039; (string): The title to display with the new content. Only if samePage=false.&lt;br /&gt;
* &#039;&#039;&#039;samePage&#039;&#039;&#039; (boolean): Whether to display the content in same page or open a new one. Defaults to new page.&lt;br /&gt;
* &#039;&#039;&#039;useOtherData&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the args for the new &#039;&#039;get_content&#039;&#039; call. The format is the same as in &#039;&#039;useOtherDataForWS&#039;&#039;. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the new &#039;&#039;get_content&#039;&#039; WS call. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins##Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to go to a new content page:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-new-content title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.viewissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to load new content in current page using userid from otherdata:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-new-content component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot; samePage=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.viewissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS when the element is clicked. The action to do when the WS call is successful depends on the provided data: display a message, go back or refresh current view.&lt;br /&gt;
&lt;br /&gt;
If you want to load a new content when the WS call is done, please see core-site-plugins-call-ws-new-content.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* preSets (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins##Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
* &#039;&#039;&#039;confirmMessage&#039;&#039;&#039; (string): Message to confirm the action when the user clicks the element. If not supplied, no confirmation. If supplied but empty, default message (&amp;quot;Are you sure?&amp;quot;).&lt;br /&gt;
* &#039;&#039;&#039;successMessage&#039;&#039;&#039; (string): Message to show on success. If not supplied, no message. If supplied but empty, default message (“Success”).&lt;br /&gt;
* &#039;&#039;&#039;goBackOnSuccess&#039;&#039;&#039; (boolean): Whether to go back if the WS call is successful.&lt;br /&gt;
* &#039;&#039;&#039;refreshOnSuccess&#039;&#039;&#039; (boolean): Whether to refresh the current view if the WS call is successful.&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to send some data to the server without using cache, displaying default messages and refreshing on success:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot; confirmMessage successMessage refreshOnSuccess=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.senddata&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to send some data to the server using cache without confirming, going back on success and using userid from otherdata:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; goBackOnSuccess=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
     {{ &#039;plugin.mod_certificate.senddata&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws-new-content====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS when the element is clicked and load a new content passing the WS result as args. This new content can be displayed in a new page or in the same page (only if current page is already displaying a site plugin content).&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t need to load some new content when done, please see core-site-plugins-call-ws.&lt;br /&gt;
&lt;br /&gt;
Data that can be passed to the directive:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins##Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
* &#039;&#039;&#039;confirmMessage&#039;&#039;&#039; (string): Message to confirm the action when the user clicks the element. If not supplied, no confirmation. If supplied but empty, default message (&amp;quot;Are you sure?&amp;quot;).&lt;br /&gt;
* &#039;&#039;&#039;component&#039;&#039;&#039; (string): The component of the new content.&lt;br /&gt;
* &#039;&#039;&#039;method&#039;&#039;&#039; (string): The method to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;args&#039;&#039;&#039; (object): The params to get the new content.&lt;br /&gt;
* &#039;&#039;&#039;title&#039;&#039;&#039; (string): The title to display with the new content. Only if samePage=false.&lt;br /&gt;
* &#039;&#039;&#039;samePage&#039;&#039;&#039; (boolean): Whether to display the content in same page or open a new one. Defaults to new page.&lt;br /&gt;
* &#039;&#039;&#039;useOtherData&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the args for the new &#039;&#039;get_content&#039;&#039; call. The format is the same as in &#039;&#039;useOtherDataForWS&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Example usages:&lt;br /&gt;
&lt;br /&gt;
A button to get some data from the server without using cache, showing default confirm and displaying a new page:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws-new-content name=&amp;quot;mod_certificate_get_issued_certificates&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot; confirmMessage title=&amp;quot;&amp;lt;% certificate.name %&amp;gt;&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A button to get some data from the server using cache, without confirm, displaying new content in same page and using &#039;&#039;userid&#039;&#039; from &#039;&#039;otherdata&#039;&#039;:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button core-site-plugins-call-ws-new-content name=&amp;quot;mod_certificate_get_issued_certificates&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; component=&amp;quot;mod_certificate&amp;quot; method=&amp;quot;mobile_issues_view&amp;quot; [args]=&amp;quot;{cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;}&amp;quot; samePage=&amp;quot;true&amp;quot; [useOtherData]=&amp;quot;[&#039;userid&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.getissued&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====core-site-plugins-call-ws-on-load====&lt;br /&gt;
&lt;br /&gt;
Directive to call a WS as soon as the template is loaded. This directive is meant for actions to do in the background, like calling logging Web Services.&lt;br /&gt;
&lt;br /&gt;
If you want to call a WS when the user clicks on a certain element, please see core-site-plugins-call-ws.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;name&#039;&#039;&#039; (string): The name of the WS to call.&lt;br /&gt;
* &#039;&#039;&#039;params&#039;&#039;&#039; (object): The params for the WS call.&lt;br /&gt;
* &#039;&#039;&#039;preSets&#039;&#039;&#039; (object): Extra options for the WS call: whether to use cache or not, etc.&lt;br /&gt;
* &#039;&#039;&#039;useOtherDataForWS&#039;&#039;&#039; (any): Whether to include &#039;&#039;otherdata&#039;&#039; (from the &#039;&#039;get_content&#039;&#039; WS call) in the params for the WS call. If not supplied, no other data will be added. If supplied but empty (null, false or empty string) all the &#039;&#039;otherdata&#039;&#039; will be added. If it’s an array, it will only copy the properties whose names are in the array.&lt;br /&gt;
* &#039;&#039;&#039;form&#039;&#039;&#039; (string): ID or name to identify a form in the template. The form will be obtained from &#039;&#039;document.forms&#039;&#039;. If supplied and form is found, the form data will be retrieved and sent to the WS. If your form contains an ion-radio, ion-checkbox or ion-select, please see [[Mobile_support_for_plugins##Values_of_ion-radio.2C_ion-checkbox_or_ion-select_aren.27t_sent_to_my_WS|Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS]].&lt;br /&gt;
&lt;br /&gt;
Example usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;span core-site-plugins-call-ws-on-load name=&amp;quot;mod_certificate_view_certificate&amp;quot; [params]=&amp;quot;{certificateid: &amp;lt;% certificate.id %&amp;gt;}&amp;quot; [preSets]=&amp;quot;{getFromCache: 0, saveToCache: 0}&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Advanced features==&lt;br /&gt;
&lt;br /&gt;
===Display the plugin only if certain conditions are met===&lt;br /&gt;
&lt;br /&gt;
You might want to display your plugin in the mobile app only if certain dynamic conditions are met, so the plugin would be displayed only for some users. This can be achieved using the &amp;quot;init&amp;quot; method (for more info, please see the [[Mobile_support_for_plugins#Initialization|Initialization]] section ahead).&lt;br /&gt;
&lt;br /&gt;
All the init methods are called as soon as your plugin is retrieved. If you don&#039;t want your plugin to be displayed for the current user, then you should return an exception in this init method. It&#039;s recommended to include a message explaining why the plugin isn&#039;t available for the current user, this exception will be logged in the Javascript console.&lt;br /&gt;
&lt;br /&gt;
On the other hand, you might want to display a plugin only for certain courses (&#039;&#039;CoreCourseOptionsDelegate&#039;&#039;) or only if the user is viewing certain users&#039; profiles (&#039;&#039;CoreUserDelegate&#039;&#039;). This can be achieved with the init method too.&lt;br /&gt;
&lt;br /&gt;
In the init method you can return a &amp;quot;restrict&amp;quot; property with two fields in it: &#039;&#039;courses&#039;&#039; and &#039;&#039;users&#039;&#039;. If you return a list of courses IDs in this restrict property, then your plugin will only be displayed when the user views any of those courses. In the same way, if you return a list of user IDs then your plugin will only be displayed when the user views any of those users&#039; profiles.&lt;br /&gt;
&lt;br /&gt;
===Using “otherdata”===&lt;br /&gt;
&lt;br /&gt;
The values returned by the functions in otherdata are added to a variable so they can be used both in Javascript and in templates. The otherdata returned by a init call is added to a variable named INIT_OTHERDATA, while the otherdata returned by a &#039;&#039;get_content&#039;&#039; WS call is added to a variable named CONTENT_OTHERDATA.&lt;br /&gt;
&lt;br /&gt;
The otherdata returned by a init call will be passed to the JS and template of all the get_content calls in that handler. The otherdata returned by a get_content call will only be passed to the JS and template returned by that get_content call.&lt;br /&gt;
&lt;br /&gt;
This means that, in your Javascript, you can access and use these data like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
this.CONTENT_OTHERDATA.myVar&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
And in the template you could use it like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
{{ CONTENT_OTHERDATA.myVar }}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;myVar&#039;&#039; is the name we put to one of our variables, it can be the name you want. In the example above, this is the otherdata returned by the PHP method:&lt;br /&gt;
&lt;br /&gt;
array(&#039;myVar&#039; =&amp;gt; &#039;Initial value&#039;)&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
In our plugin we want to display an input text with a certain initial value. When the user clicks a button, we want the value in the input to be sent to a certain WebService. This can be done using otherdata.&lt;br /&gt;
&lt;br /&gt;
We will return the initial value of the input in the otherdata of our PHP method:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;myVar&#039; =&amp;gt; &#039;My initial value&#039;),&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Then in the template we will use it like this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-item text-wrap&amp;gt;&lt;br /&gt;
    &amp;lt;ion-label stacked&amp;gt;{{ &#039;plugin.mod_certificate.textlabel | translate }}&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
    &amp;lt;ion-input type=&amp;quot;text&amp;quot; [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.myVar&amp;quot;&amp;gt;&amp;lt;/ion-input&amp;gt;&lt;br /&gt;
&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;ion-item&amp;gt;&lt;br /&gt;
    &amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-call-ws name=&amp;quot;mod_certificate_my_webservice&amp;quot; [useOtherDataForWS]=&amp;quot;[&#039;myVar&#039;]&amp;quot;&amp;gt;&lt;br /&gt;
        {{ &#039;plugin.mod_certificate.send | translate }}&lt;br /&gt;
    &amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we are creating an input text and we use &#039;&#039;[(ngModel)]&#039;&#039; to use the value in &#039;&#039;myVar&#039;&#039; as the initial value and to store the changes in the same &#039;&#039;myVar&#039;&#039; variable. This means that the initial value of the input will be “My initial value”, and if the user changes the value of the input these changes will be applied to the &#039;&#039;myVar&#039;&#039; variable. This is called 2-way data binding in Angular.&lt;br /&gt;
&lt;br /&gt;
Then we add a button to send this data to a WS, and for that we use the directive core-site-plugins-call-ws. We use the &#039;&#039;useOtherDataForWS&#039;&#039; attribute to specify which variable from &#039;&#039;otherdata&#039;&#039; we want to send to our WebService. So if the user enters “A new value” in the input and then clicks the button, it will call the WebService &#039;&#039;mod_certificate_my_webservice&#039;&#039; and will send as a param: myVar -&amp;gt; “A new value”.&lt;br /&gt;
&lt;br /&gt;
We can achieve the same result using the &#039;&#039;params&#039;&#039; attribute of the core-site-plugins-call-ws directive instead of using &#039;&#039;useOtherDataForWS&#039;&#039;:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block color=&amp;quot;light&amp;quot; core-site-plugins-call-ws name=&amp;quot;mod_certificate_my_webservice&amp;quot; [params]=&amp;quot;{myVar: CONTENT_OTHERDATA.myVar}&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mod_certificate.send | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The WebService call will be exactly the same with both buttons.&lt;br /&gt;
&lt;br /&gt;
Please notice that this example could be done without using otherdata too, using the “&#039;&#039;form&#039;&#039;” input of the &#039;&#039;core-site-plugins-call-ws directive&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===JS functions visible in the templates===&lt;br /&gt;
&lt;br /&gt;
The app provides some Javascript functions that can be used from the templates to update, refresh or view content. These are the functions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;openContent(title: string, args: any, component?: string, method?: string)&#039;&#039;&#039;: Open a new page to display some new content. You need to specify the &#039;&#039;title&#039;&#039; of the new page and the &#039;&#039;args&#039;&#039; to send to the method. If &#039;&#039;component&#039;&#039; and &#039;&#039;method&#039;&#039; aren&#039;t provided, it will use the same as in the current page.&lt;br /&gt;
* &#039;&#039;&#039;refreshContent(showSpinner = true)&#039;&#039;&#039;: Refresh the current content. By default it will display a spinner while refreshing, if you don&#039;t want it to be displayed you should pass false as a parameter.&lt;br /&gt;
* &#039;&#039;&#039;updateContent(args: any, component?: string, method?: string)&#039;&#039;&#039;: Refresh the current content using different params. You need to specify the &#039;&#039;args&#039;&#039; to send to the method. If &#039;&#039;component&#039;&#039; and &#039;&#039;method&#039;&#039; aren&#039;t provided, it will use the same as in the current page.&lt;br /&gt;
&lt;br /&gt;
====Examples====&lt;br /&gt;
&lt;br /&gt;
=====Group selector=====&lt;br /&gt;
&lt;br /&gt;
Imagine we have an activity that uses groups and we want to let the user select which group he wants to see. A possible solution would be to return all the groups in the same template (hidden), and then show the group user selects. However, we can make it more dynamic and return only the group the user is requesting.&lt;br /&gt;
&lt;br /&gt;
To do so, we&#039;ll use a drop down to select the group. When the user selects a group using this drop down we&#039;ll update the page content to display the new group.&lt;br /&gt;
&lt;br /&gt;
The main difficulty in this is to tell the view which group needs to be selected when the view is loaded. There are 2 ways to do it: using plain HTML or using Angular&#039;s &#039;&#039;ngModel&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
======Using plain HTML======&lt;br /&gt;
&lt;br /&gt;
We need to add a &amp;quot;&#039;&#039;selected&#039;&#039;&amp;quot; attribute to the option that needs to be selected. To do so, we need to pre-caclulate the selected option in the PHP code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $groupid = empty($args-&amp;gt;group) ? 0 : $args-&amp;gt;group; // By default, group 0.&lt;br /&gt;
        $groups = groups_get_activity_allowed_groups($cm, $user-&amp;gt;id);&lt;br /&gt;
        // Detect which group is selected.&lt;br /&gt;
        foreach ($groups as $gid=&amp;gt;$group) {&lt;br /&gt;
            $group-&amp;gt;selected = $gid === $groupid;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $data = array(&lt;br /&gt;
            &#039;cmid&#039; =&amp;gt; $cm-&amp;gt;id,&lt;br /&gt;
            &#039;courseid&#039; =&amp;gt; $args-&amp;gt;courseid,&lt;br /&gt;
            &#039;groups&#039; =&amp;gt; $groups&lt;br /&gt;
        );&lt;br /&gt;
&lt;br /&gt;
        return array(&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
        );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the code above, we&#039;re retrieving the groups the user can see and then we&#039;re adding a &amp;quot;selected&amp;quot; bool to each one to determine which one needs to be selected in the drop down. Finally, we pass the list of groups to the template.&lt;br /&gt;
&lt;br /&gt;
In the template, we display the drop down like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-select (ionChange)=&amp;quot;updateContent({cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;, group: $event})&amp;quot; interface=&amp;quot;popover&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;%#groups%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-option value=&amp;quot;&amp;lt;% id %&amp;gt;&amp;quot; &amp;lt;%#selected%&amp;gt;selected&amp;lt;%/selected%&amp;gt; &amp;gt;&amp;lt;% name %&amp;gt;&amp;lt;/ion-option&amp;gt;&lt;br /&gt;
    &amp;lt;%/groups%&amp;gt;&lt;br /&gt;
&amp;lt;/ion-select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;ionChange&#039;&#039; function will be called everytime the user selects a different group with the drop down. We&#039;re using the function &#039;&#039;updateContent&#039;&#039; to update the current view using the new group. &#039;&#039;$event&#039;&#039; is an Angular variable that will have the selected value (in our case, the group ID that was just selected). This is enough to make the group selector work.&lt;br /&gt;
&lt;br /&gt;
======Using ngModel======&lt;br /&gt;
&lt;br /&gt;
ngModel is an Angular directive that allows storing the value of a certain input/select in a Javascript variable, and also the opposite way: tell the input/select which value to set. The main problem is that we cannot initialize a Javascript variable from the template (Angular doesn&#039;t have &#039;&#039;ng-init&#039;&#039; like in AngularJS), so we&#039;ll use &amp;quot;otherdata&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In the PHP function we&#039;ll return the group that needs to be selected in the &#039;&#039;otherdata&#039;&#039; array:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $groupid = empty($args-&amp;gt;group) ? 0 : $args-&amp;gt;group; // By default, group 0.&lt;br /&gt;
        $groups = groups_get_activity_allowed_groups($cm, $user-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
         ...&lt;br /&gt;
&lt;br /&gt;
         return array(&lt;br /&gt;
            &#039;templates&#039; =&amp;gt; array(&lt;br /&gt;
                array(&lt;br /&gt;
                    &#039;id&#039; =&amp;gt; &#039;main&#039;,&lt;br /&gt;
                    &#039;html&#039; =&amp;gt; $OUTPUT-&amp;gt;render_from_template(&#039;mod_certificate/mobile_view_page&#039;, $data),&lt;br /&gt;
                ),&lt;br /&gt;
            ),&lt;br /&gt;
            &#039;otherdata&#039; =&amp;gt; array(&lt;br /&gt;
                &#039;group&#039; =&amp;gt; $groupid&lt;br /&gt;
            ),&lt;br /&gt;
        );&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above we don&#039;t need to iterate over the groups array like in the plain HTML example. However, now we&#039;re returning the groupid in the &amp;quot;otherdata&amp;quot; array. As it&#039;s explained in the [[Mobile_support_for_plugins#Using_.E2.80.9Cotherdata.E2.80.9D|Using &amp;quot;otherdata&amp;quot;]] section, this &amp;quot;otherdata&amp;quot; is visible in the templates inside a variable named &#039;&#039;CONTENT_OTHERDATA&#039;&#039;. So in the template we&#039;ll use this variable like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;ion-select [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.group&amp;quot; (ionChange)=&amp;quot;updateContent({cmid: &amp;lt;% cmid %&amp;gt;, courseid: &amp;lt;% courseid %&amp;gt;, group: CONTENT_OTHERDATA.group})&amp;quot; interface=&amp;quot;popover&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;%#groups%&amp;gt;&lt;br /&gt;
        &amp;lt;ion-option value=&amp;quot;&amp;lt;% id %&amp;gt;&amp;quot;&amp;gt;&amp;lt;% name %&amp;gt;&amp;lt;/ion-option&amp;gt;&lt;br /&gt;
    &amp;lt;%/groups%&amp;gt;&lt;br /&gt;
&amp;lt;/ion-select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Initialization===&lt;br /&gt;
&lt;br /&gt;
All handlers can specify a “&#039;&#039;init&#039;&#039;” method in the mobile.php file. This method is meant to return some JavaScript code that needs to be executed as soon as the plugin is retrieved.&lt;br /&gt;
&lt;br /&gt;
When the app retrieves all the handlers, the first thing it will do is call the &#039;&#039;tool_mobile_get_content&#039;&#039; WebService with the init method. This WS call will only receive the default args.&lt;br /&gt;
&lt;br /&gt;
The app will immediately execute the JavaScript code returned by this WS call. This JavaScript can be used to manually register your handlers in the delegates you want, without having to rely on the default handlers built based on the mobile.php data.&lt;br /&gt;
&lt;br /&gt;
The templates returned by this init method will be added to a INIT_TEMPLATES variable that will be passed to all the Javascript code of that handler. This means that the Javascript returned by the init method or the “main” method can access any of the templates HTML like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.INIT_TEMPLATES[‘main’];&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In this case, “main” is the ID of the template we want to use.&lt;br /&gt;
&lt;br /&gt;
The same happens with the &#039;&#039;otherdata&#039;&#039; returned by this init method, it is added to a INIT_OTHERDATA variable.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;restrict&#039;&#039; field returned by this init call will be used to determine if your handler is enabled or not. For example, if your handler is for the delegate &#039;&#039;CoreCourseOptionsDelegate&#039;&#039; and you return a list of courseids in restrict-&amp;gt;courses, then your handler will only be enabled in the courses you returned. This only applies to the “default” handlers, if you register your own handler using the Javascript code then you should check yourself if the handler is enabled.&lt;br /&gt;
&lt;br /&gt;
Finally, if you return an object in this init Javascript code, all the properties of that object will be passed to all the Javascript code of that handler so you can use them when the code is run. For example, if your init Javascript code does something like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var result = {&lt;br /&gt;
    MyAddonClass: new MyAddonClass()&lt;br /&gt;
};&lt;br /&gt;
result:&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Then, for the rest of Javascript code of your handler (e.g. for the “main” method) you can use this variable like this:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
this.MyAddonClass&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Examples====&lt;br /&gt;
&lt;br /&gt;
=====Module link handler=====&lt;br /&gt;
&lt;br /&gt;
A link handler allows you to decide what to do when a link with a certain URL is clicked. This is useful, for example, to open your module when a link to the module is clicked. In this example we’ll create a link handler to detect links to a certificate module using a init JavaScript:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function AddonModCertificateModuleLinkHandler() {&lt;br /&gt;
    that.CoreContentLinksModuleIndexHandler.call(this, that.CoreCourseHelperProvider, &#039;mmaModCertificate&#039;, &#039;certificate&#039;);&lt;br /&gt;
&lt;br /&gt;
    this.name = &amp;quot;AddonModCertificateLinkHandler&amp;quot;;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModuleLinkHandler.prototype = Object.create(this.CoreContentLinksModuleIndexHandler.prototype);&lt;br /&gt;
AddonModCertificateModuleLinkHandler.prototype.constructor = AddonModCertificateModuleLinkHandler;&lt;br /&gt;
&lt;br /&gt;
this.CoreContentLinksDelegate.registerHandler(new AddonModCertificateModuleLinkHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Module prefetch handler=====&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;CoreCourseModuleDelegate&#039;&#039; handler allows you to define a list of &#039;&#039;offlinefunctions&#039;&#039; to prefetch a module. However, you might want to create your own prefetch handler to determine what needs to be downloaded. For example, you might need to chain WS calls (pass the result of a WS call to the next one), and this cannot be done using &#039;&#039;offlinefunctions&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Here’s an example on how to create a prefetch handler using init JS:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function AddonModCertificateModulePrefetchHandler() {&lt;br /&gt;
    that.CoreCourseModulePrefetchHandlerBase.call(this, that.injector);&lt;br /&gt;
&lt;br /&gt;
    this.name = &amp;quot;certificate&amp;quot;;&lt;br /&gt;
    this.component = &amp;quot;mmaModCertificate&amp;quot;;&lt;br /&gt;
    this.updatesNames = /^configuration$|^.*files$/;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype = Object.create(this.CoreCourseModulePrefetchHandlerBase.prototype);&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype.constructor = AddonModCertificateModulePrefetchHandler;&lt;br /&gt;
&lt;br /&gt;
AddonModCertificateModulePrefetchHandler.prototype.downloadOrPrefetch = function(module, courseId, prefetch, dirPath) {&lt;br /&gt;
&lt;br /&gt;
    var promises = [];&lt;br /&gt;
&lt;br /&gt;
    promises.push(that.CoreCourseModulePrefetchHandlerBase.prototype.downloadOrPrefetch.call(this, module, courseId, prefetch, dirPath));&lt;br /&gt;
&lt;br /&gt;
    promises.push(that.sitesProvider.getCurrentSite().read(&amp;quot;mod_certificate_get_certificates_by_courses&amp;quot;, {courseids: [courseId]}));&lt;br /&gt;
&lt;br /&gt;
return Promise.all(promises);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
this.CoreCourseModulePrefetchDelegate.registerHandler(new AddonModCertificateModulePrefetchHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====Single activity course format=====&lt;br /&gt;
&lt;br /&gt;
In the following example, the value of INIT_TEMPLATES[&amp;quot;main&amp;quot;] is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;core-dynamic-component [component]=&amp;quot;componentClass&amp;quot; [data]=&amp;quot;data&amp;quot;&amp;gt;&amp;lt;/core-dynamic-component&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This template is returned by the init method. And this is the JavaScript code returned by the init method:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
function getAddonSingleActivityFormatComponent() {&lt;br /&gt;
    function AddonSingleActivityFormatComponent() {&lt;br /&gt;
        this.data = {};&lt;br /&gt;
    };&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.constructor = AddonSingleActivityFormatComponent;&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.ngOnChanges = function(changes) {&lt;br /&gt;
        var self = this;&lt;br /&gt;
&lt;br /&gt;
        if (this.course &amp;amp;&amp;amp; this.sections &amp;amp;&amp;amp; this.sections.length) {&lt;br /&gt;
            var module = this.sections[0] &amp;amp;&amp;amp; this.sections[0].modules &amp;amp;&amp;amp; this.sections[0].modules[0];&lt;br /&gt;
            if (module &amp;amp;&amp;amp; !this.componentClass) {&lt;br /&gt;
                that.CoreCourseModuleDelegate.getMainComponent(that.Injector, this.course, module).then((component) =&amp;gt; {&lt;br /&gt;
                    self.componentClass = component || that.CoreCourseUnsupportedModuleComponent;&lt;br /&gt;
                });&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            this.data.courseId = this.course.id;&lt;br /&gt;
            this.data.module = module;&lt;br /&gt;
        }&lt;br /&gt;
    };&lt;br /&gt;
    AddonSingleActivityFormatComponent.prototype.doRefresh = function(refresher, done) {&lt;br /&gt;
        return Promise.resolve(this.dynamicComponent.callComponentFunction(&amp;quot;doRefresh&amp;quot;, [refresher, done]));&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
return AddonSingleActivityFormatComponent;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
function AddonSingleActivityFormatHandler() {&lt;br /&gt;
    this.name = &amp;quot;singleactivity&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.constructor = AddonSingleActivityFormatHandler;&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.isEnabled = function() {&lt;br /&gt;
    return true;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.canViewAllSections = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.getCourseTitle = function(course, sections) {&lt;br /&gt;
    if (sections &amp;amp;&amp;amp; sections[0] &amp;amp;&amp;amp; sections[0].modules &amp;amp;&amp;amp; sections[0].modules[0]) {&lt;br /&gt;
        return sections[0].modules[0].name;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return course.fullname || &amp;quot;&amp;quot;;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.displayEnableDownload = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.displaySectionSelector = function(course) {&lt;br /&gt;
    return false;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
AddonSingleActivityFormatHandler.prototype.getCourseFormatComponent = function(injector, course) {&lt;br /&gt;
    that.Injector = injector || that.Injector;&lt;br /&gt;
&lt;br /&gt;
    return that.CoreCompileProvider.instantiateDynamicComponent(that.INIT_TEMPLATES[&amp;quot;main&amp;quot;], getAddonSingleActivityFormatComponent(), injector);&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
this.CoreCourseFormatDelegate.registerHandler(new AddonSingleActivityFormatHandler());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Using the JavaScript API===&lt;br /&gt;
&lt;br /&gt;
The Javascript API is partly supported right now, only the &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; supports it now. This API allows you to override any of the functions of the default handler. &lt;br /&gt;
&lt;br /&gt;
The “method” specified in a handler registered in the &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; will be called immediately after the init method, and the Javascript returned by this method will be run. If this Javascript code returns an object with certain functions, these function will override the ones in the default handler.&lt;br /&gt;
&lt;br /&gt;
For example, if the Javascript returned by the method returns something like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var result = {&lt;br /&gt;
    getData: function(field, signup, registerAuth, formValues) {&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
result;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The the &#039;&#039;getData&#039;&#039; function of the default handler will be overridden by the returned getData function.&lt;br /&gt;
&lt;br /&gt;
The default handler for &#039;&#039;CoreUserProfileFieldDelegate&#039;&#039; only has 2 functions: &#039;&#039;getComponent&#039;&#039; and &#039;&#039;getData&#039;&#039;. In addition, the JavaScript code can return an extra function named &#039;&#039;componentInit&#039;&#039; that will be executed when the component returned by &#039;&#039;getComponent&#039;&#039; is initialized.&lt;br /&gt;
&lt;br /&gt;
Here’s an example on how to support the text user profile field using this API:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
var that = this;&lt;br /&gt;
&lt;br /&gt;
var result = {&lt;br /&gt;
    componentInit: function() {&lt;br /&gt;
        if (this.field &amp;amp;&amp;amp; this.edit &amp;amp;&amp;amp; this.form) {&lt;br /&gt;
            this.field.modelName = &amp;quot;profile_field_&amp;quot; + this.field.shortname;&lt;br /&gt;
&lt;br /&gt;
            if (this.field.param2) {&lt;br /&gt;
                this.field.maxlength = parseInt(this.field.param2, 10) || &amp;quot;&amp;quot;;&lt;br /&gt;
            }&lt;br /&gt;
&lt;br /&gt;
            this.field.inputType = that.CoreUtilsProvider.isTrueOrOne(this.field.param3) ? &amp;quot;password&amp;quot; : &amp;quot;text&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
            var formData = {&lt;br /&gt;
                value: this.field.defaultdata,&lt;br /&gt;
                disabled: this.disabled&lt;br /&gt;
            };&lt;br /&gt;
&lt;br /&gt;
            this.form.addControl(this.field.modelName, that.FormBuilder.control(formData, this.field.required &amp;amp;&amp;amp; !this.field.locked ? that.Validators.required : null));&lt;br /&gt;
        }&lt;br /&gt;
    },&lt;br /&gt;
    getData: function(field, signup, registerAuth, formValues) {&lt;br /&gt;
        var name = &amp;quot;profile_field_&amp;quot; + field.shortname;&lt;br /&gt;
&lt;br /&gt;
        return {&lt;br /&gt;
            type: &amp;quot;text&amp;quot;,&lt;br /&gt;
            name: name,&lt;br /&gt;
            value: that.CoreTextUtilsProvider.cleanTags(formValues[name])&lt;br /&gt;
        };&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
result;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Troubleshooting==&lt;br /&gt;
&lt;br /&gt;
=== Invalid response received ===&lt;br /&gt;
&lt;br /&gt;
You might receive this error when using the &amp;quot;core-site-plugins-call-ws&amp;quot; directive or similar. By default, the app expects all WebService calls to return an object, if your WebService returns another type (string, bool, ...) then you need to specify it using the preSets attribute of the directive. For example, if your WS returns a boolean value, then you should specify it like this:&lt;br /&gt;
&lt;br /&gt;
[preSets]=&amp;quot;{typeExpected: &#039;boolean&#039;}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
In a similar way, if your WebService returns null you need to tell the app not to expect any result using the preSets:&lt;br /&gt;
&lt;br /&gt;
[preSets]=&amp;quot;{responseExpected: false}&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Values of ion-radio, ion-checkbox or ion-select aren&#039;t sent to my WS ===&lt;br /&gt;
&lt;br /&gt;
Some directives allow you to specify a form id or name to send the data from the form to a certain WS. These directives look for HTML inputs to retrieve the data to send. However, ion-radio, ion-checkbox and ion-select don&#039;t use HTML inputs, they simulate them, so the directive isn&#039;t going to find their data and so it won&#039;t be sent to the WebService.&lt;br /&gt;
&lt;br /&gt;
There are 2 workarounds to fix this problem. It seems that the next major release of Ionic framework does use HTML inputs, so these are temporary solutions.&lt;br /&gt;
&lt;br /&gt;
==== Sending the data manually ====&lt;br /&gt;
&lt;br /&gt;
The first solution is to send the missing params manually using the &amp;quot;&#039;&#039;params&#039;&#039;&amp;quot; property. We will use &#039;&#039;ngModel&#039;&#039; to store the input value in a variable, and this variable will be passed to the params. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too.&lt;br /&gt;
&lt;br /&gt;
For example, if you have a template like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;myws&amp;quot; [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;}&amp;quot; form=&amp;quot;myform&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mycomponent.save&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you should modify it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot; [(ngModel)]=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;myws&amp;quot; [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;, responses: responses}&amp;quot; form=&amp;quot;myform&amp;quot;&amp;gt;&lt;br /&gt;
    {{ &#039;plugin.mycomponent.save&#039; | translate }}&lt;br /&gt;
&amp;lt;/button&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Basically, you need to add &#039;&#039;ngModel&#039;&#039; to the affected element (in this case, the &#039;&#039;radio-group&#039;&#039;). You can put whatever name you want as the value, we used &amp;quot;responses&amp;quot;. With this, everytime the user selects a radio button the value will be stored in a variable named &amp;quot;responses&amp;quot;. Then, in the button we are passing this variable to the params of the WebService.&lt;br /&gt;
&lt;br /&gt;
Please notice that the &amp;quot;form&amp;quot; attribute has priority over &amp;quot;params&amp;quot;, so if you have an input with name=&amp;quot;responses&amp;quot; it will override what you&#039;re manually passing to params.&lt;br /&gt;
&lt;br /&gt;
==== Using a hidden input ====&lt;br /&gt;
&lt;br /&gt;
Since the directive is looking for HTML inputs, you need to add one with the value to send to the server. You can use &#039;&#039;ngModel&#039;&#039; to synchronize your ion-radio/ion-checkbox/ion-select with the new hidden input. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too.&lt;br /&gt;
&lt;br /&gt;
For example, if you have a radio button like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then you should modify it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;div radio-group name=&amp;quot;responses&amp;quot; [(ngModel)]=&amp;quot;responses&amp;quot;&amp;gt; &lt;br /&gt;
    &amp;lt;ion-item&amp;gt;&lt;br /&gt;
        &amp;lt;ion-label&amp;gt;First value&amp;lt;/ion-label&amp;gt;&lt;br /&gt;
        &amp;lt;ion-radio value=&amp;quot;1&amp;quot;&amp;gt;&amp;lt;/ion-radio&amp;gt;&lt;br /&gt;
    &amp;lt;/ion-item&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    &amp;lt;ion-input type=&amp;quot;hidden&amp;quot; [ngModel]=&amp;quot;responses&amp;quot; name=&amp;quot;responses&amp;quot;&amp;gt;&amp;lt;/ion-input&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In the example above, we&#039;re using a variable named &amp;quot;responses&amp;quot; to synchronize the data between the &#039;&#039;radio-group&#039;&#039; and the hidden input. You can use whatever name you want.&lt;br /&gt;
&lt;br /&gt;
=== I can&#039;t return an object or array in otherdata ===&lt;br /&gt;
&lt;br /&gt;
If you try to return an object or an array in any field inside &#039;&#039;otherdata&#039;&#039;, the WebService call will fail with the following error:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Scalar type expected, array or object received&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Each field in &#039;&#039;otherdata&#039;&#039; must be a string, number or boolean, it cannot be an object or array. To make it work, you need to encode your object or array into a JSON string:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; json_encode($data))&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The app will automatically parse this JSON and convert it back into an array or object.&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===Accepting dynamic names in a WebService===&lt;br /&gt;
&lt;br /&gt;
We want to display a form where the names of the fields are dynamic, like it happens in quiz. This data will be sent to a new WebService that we have created.&lt;br /&gt;
&lt;br /&gt;
The first issue we find is that the WebService needs to define the names of the parameters received, but in this case they&#039;re dynamic. The solution is to accept an array of objects with name and value. So in the &#039;&#039;_parameters()&#039;&#039; function of our new WebService, we will add this parameter:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;data&#039; =&amp;gt; new external_multiple_structure(&lt;br /&gt;
     new external_single_structure(&lt;br /&gt;
        array(&lt;br /&gt;
            &#039;name&#039; =&amp;gt; new external_value(PARAM_RAW, &#039;data name&#039;),&lt;br /&gt;
            &#039;value&#039; =&amp;gt; new external_value(PARAM_RAW, &#039;data value&#039;),&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
    &#039;The data to be saved&#039;, VALUE_DEFAULT, array()&lt;br /&gt;
)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we need to adapt our form to send the data as the WebService requires it. In our template, we have a button with the directive &#039;&#039;core-site-plugins-call-ws&#039;&#039; that will send the form data to our WebService. To make this work we will have to pass the parameters manually, without using the &amp;quot;&#039;&#039;form&#039;&#039;&amp;quot; attribute, because we need to format the data before it is sent.&lt;br /&gt;
&lt;br /&gt;
Since we will send the params manually and we want it all to be sent in the same array, we will use &#039;&#039;ngModel&#039;&#039; to store the input data into a variable that we&#039;ll call &amp;quot;data&amp;quot;, but you can use the name you want. This &amp;quot;data&amp;quot; will be an object that will hold the input data with the format &amp;quot;name-&amp;gt;value&amp;quot;. For example, if I have an input with name &amp;quot;a1&amp;quot; and value &amp;quot;My answer&amp;quot;, the data object will be:&lt;br /&gt;
&lt;br /&gt;
{a1: &amp;quot;My answer&amp;quot;}&lt;br /&gt;
&lt;br /&gt;
So we need to add &#039;&#039;ngModel&#039;&#039; to all the inputs whose values need to be sent to the &amp;quot;data&amp;quot; WS param. Please notice that &#039;&#039;ngModel&#039;&#039; &#039;&#039;&#039;requires&#039;&#039;&#039; the element to have a name, so if you add &#039;&#039;ngModel&#039;&#039; to a certain element you need to add a name too. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&amp;lt;ion-input name=&amp;quot;&amp;lt;% name %&amp;gt;&amp;quot; [(ngModel)]=&amp;quot;CONTENT_OTHERDATA.data[&#039;&amp;lt;% name %&amp;gt;&#039;]&amp;quot;&amp;gt;&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, we&#039;re using &#039;&#039;CONTENT_OTHERDATA&#039;&#039; to store the data. We do it like this because we&#039;ll use &#039;&#039;otherdata&#039;&#039; to initialize the form, setting the values the user has already stored. If you don&#039;t need to initialize the form, then you can use the variable &amp;quot;dataObject&amp;quot;, an empty object that the Mobile app creates for you: [(ngModel)]=&amp;quot;dataObject[&#039;&amp;lt;% name %&amp;gt;&#039;]&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The Mobile app has a function that allows you to convert this data object into an array like the one the WS expects: &#039;&#039;objectToArrayOfObjects&#039;&#039;. So in our button we&#039;ll use this function to format the data before it&#039;s sent:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&amp;lt;button ion-button block type=&amp;quot;submit&amp;quot; core-site-plugins-call-ws name=&amp;quot;my_ws_name&amp;quot;&lt;br /&gt;
    [params]=&amp;quot;{id: &amp;lt;% id %&amp;gt;, data: CoreUtilsProvider.objectToArrayOfObjects(CONTENT_OTHERDATA.data, &#039;name&#039;, &#039;value&#039;)}&amp;quot;&lt;br /&gt;
    successMessage&lt;br /&gt;
    refreshOnSuccess=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see in the example above, we&#039;re specifying that the keys of the &amp;quot;data&amp;quot; object need to be stored in a property named &amp;quot;name&amp;quot;, and the values need to be stored in a property named &amp;quot;value&amp;quot;. If your WebService expects different names you need to change the parameters of the function &#039;&#039;objectToArrayOfObjects&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
If you open your plugin now in the Mobile app it will display an error in the Javascript console. The reason is that the variable &amp;quot;data&amp;quot; doesn&#039;t exist inside &#039;&#039;CONTENT_OTHERDATA&#039;&#039;. As it is explained in previous sections, &#039;&#039;CONTENT_OTHERDATA&#039;&#039; holds the data that you return in &#039;&#039;otherdata&#039;&#039; for your method. We&#039;ll use &#039;&#039;otherdata&#039;&#039; to initialize the values to be displayed in the form.&lt;br /&gt;
&lt;br /&gt;
If the user hasn&#039;t answered the form yet, we can initialize the &amp;quot;data&amp;quot; object as an empty object. Please remember that we cannot return arrays or objects in &#039;&#039;otherdata&#039;&#039;, so we&#039;ll return a JSON string.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; &#039;{}&#039;)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With the code above, the form will always be empty when the user opens it. But now we want to check if the user has already answered the form and fill the form with the previous values. We will do it like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$userdata = get_user_responses(); // It will held the data in a format name-&amp;gt;value. Example: array(&#039;a1&#039; =&amp;gt; &#039;My value&#039;).&lt;br /&gt;
...&lt;br /&gt;
&#039;otherdata&#039; =&amp;gt; array(&#039;data&#039; =&amp;gt; json_encode($userdata))&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now the user will be able to see previous values when the form is opened, and clicking the button will send the data to our WebService in array format.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Mobile]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_App_Release_Process&amp;diff=54379</id>
		<title>Moodle App Release Process</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_App_Release_Process&amp;diff=54379"/>
		<updated>2018-06-12T14:03:34Z</updated>

		<summary type="html">&lt;p&gt;Fox: Typos&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== 4-7 days before (when possible) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| Create an issue in the tracker for the release, like: MOBILE-1248&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| Update the local_moodlemobileapp plugin with new strings in moodle.org/plugins (only for Moodle version 2.6). Use the moodlemobile-scripts/json-to-string2.php to convert the build lang file to a valid string file. &lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| Ask someone from sites or community team to review the new english strings. &lt;br /&gt;
| Community or Sites team&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| Announce in the moodletranslation forums the new strings available: https://lang.moodle.org/mod/forum/view.php?id=5. This will allow translators to add the new strings during the days prior to the release.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| Add the release notes in the release issue created (search for the [https://tracker.moodle.org/issues/?jql=project%20%3D%20MOBILE%20AND%20labels%20%3D%20release_notes release_notes tag]). Ask someone from the documentation team or Martin to review the release notes.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
| Contact the marketing announcing the new release and highlights.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 7 days before (testing days) ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| Create a new local branch (based on moodlehq/moodlemobile2:integration) with the release tracker issue number for integrating all the version and string changes.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| Run gulp and then execute detect-string-core-changes.php and auto-translate strings with the script auto-translate2.php, commiting the results.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| Run gulp and update language strings from AMOS using the fetch-langpacks2.sh script, commit the result.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| Bump version numbers in config.xml, www/config.json, package.json, desktop/assets/windows/AppXManifest.xml and in www/errorreport.js (is hardcoded there).&lt;br /&gt;
Push all this changes using the release issue number and integrate them into the integration branch.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| Execute the prepare-release-integration.sh script to update the moodlehq/moodlemobile-phonegap build:integration branch with a built version of the app ready for PhonegapBuild. &lt;br /&gt;
Push all this changes to moodlehq/moodlemobile-phonegapbuild:integration.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
| Bump version numbers in moodlehq/moodlemobile-phonegapbuild:integration/config.xml and push the changes.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
| Create a build in Phonegap Build using the Development certificate for iOs and the production keystore for Android pointing to moodlehq/moodlemobile-phonegap build:integration&lt;br /&gt;
And &#039;&#039;&#039;Start testing&#039;&#039;&#039;&lt;br /&gt;
| All the team&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== 1 day before ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| Backport to local_mobile (all branches) all the new required Web Services by new features.&lt;br /&gt;
Check if existing Web Services should be added to the local_mobile service (because they were added to the Mobile app service).&lt;br /&gt;
&lt;br /&gt;
Once all the Web Services are backported and tested, publish a new version in the plugins database (via TAGS) so admin can updates their sites.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== The release day ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;table table-striped table-bordered&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! style=&amp;quot;width:20px&amp;quot; | #&lt;br /&gt;
! Task&lt;br /&gt;
! style=&amp;quot;width:12%&amp;quot; | Responsibility&lt;br /&gt;
|-&lt;br /&gt;
| 1.&lt;br /&gt;
| Integrate the [https://github.com/moodlehq/moodlemobile2/compare/master...integration integration branch onto the master one].  Execute the prepare-release-version.sh script.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 2.&lt;br /&gt;
| Bump the versions in the config.xml file and then PUSH the master branch of the moodlemobile-phonegapbuild repository.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 3.&lt;br /&gt;
| Build the app for Android and iOs using the Distribution certificate. Remember to do two different builds (pointing to the ios and android branches).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 4.&lt;br /&gt;
| Send the applications to the stores for review. Update the download.php for desktop apps (including new version number).&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 5.&lt;br /&gt;
| Update release notes [[Moodle_Mobile_Release_Notes]] and  [[Moodle_Desktop_release_notes]]  with the notes reviewed in the issue.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 6.&lt;br /&gt;
| Create a TAG/Release in github ([https://github.com/moodlehq/moodlemobile2/releases moodlehq/moodlemobile2]) with the version number.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 7.&lt;br /&gt;
| Update the [https://moodle.org/plugins/view/local_mobile local mobile plugin] short description to indicate which is the latest Moodle Mobile version supported and date.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 8.&lt;br /&gt;
| Mark the issue and the [https://tracker.moodle.org/projects/MOBILE?selectedItem=com.atlassian.jira.jira-projects-plugin:release-page version] as released in the tracker.&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|-&lt;br /&gt;
| 9.&lt;br /&gt;
| Social media announcements (Forum and Twitter).&lt;br /&gt;
| All the team &amp;amp; Marketing team &lt;br /&gt;
|-&lt;br /&gt;
| 10.&lt;br /&gt;
| Post in moodle.org/news.&lt;br /&gt;
| Team Lead&lt;br /&gt;
|-&lt;br /&gt;
| 11.&lt;br /&gt;
| Review the users and developers documentation (check that everything is in order). Review the [https://tracker.moodle.org/issues/?jql=project%20%3D%20MOBILE%20AND%20labels%20in%20%28docs_required%2C%20dev_docs_required%29 docs_required and dev_docs_required_tags]. Review the [https://docs.moodle.org/en/Moodle_Mobile_features Mobile features wiki documentation].&lt;br /&gt;
| All the team&lt;br /&gt;
|-&lt;br /&gt;
| 12.&lt;br /&gt;
| Provide the APK file for including in [https://download.moodle.org/mobile/ Moodle downloads: Moodle mobile].&lt;br /&gt;
| Integration Lead&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
[[Category:Processes]]&lt;br /&gt;
[[Category:Mobile]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.4.3_release_notes&amp;diff=54185</id>
		<title>Moodle 3.4.3 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.4.3_release_notes&amp;diff=54185"/>
		<updated>2018-05-16T09:13:00Z</updated>

		<summary type="html">&lt;p&gt;Fox: Correct language links&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 14 May 2018 (Not yet released)&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.4.3%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.4.3].&lt;br /&gt;
 &lt;br /&gt;
===GDPR preparation===&lt;br /&gt;
&lt;br /&gt;
Plugins are available for Moodle 3.3 and 3.4 to help Moodle sites to comply with GDPR - [https://moodle.org/plugins/tool_dataprivacy Data privacy], [https://moodle.org/plugins/tool_policy Policies]. In Moodle 3.5 they will be included in the standard distribution. Work on changes in core is almost completed, the new minor release with the remaining components will follow in several days.&lt;br /&gt;
* MDL-61306 - Implement privacy API in various components and standard plugins for user data export and deletion&lt;br /&gt;
 &lt;br /&gt;
===Fixes and improvements===&lt;br /&gt;
 &lt;br /&gt;
* MDL-58697 - Assignment: Fixed incorrect &amp;quot;No submission&amp;quot; status if group submission changed to individual submission&lt;br /&gt;
* MDL-61724 - File resource: Fixed download problem for files with long names&lt;br /&gt;
* MDL-61519 - Performance improvement in Calendar in case of big number of course categories&lt;br /&gt;
* MDL-55532 - Show grade category name in Grades Export&lt;br /&gt;
* MDL-61714 - GDPR and privacy: Change default age of digital consent according to current legislation on each country&lt;br /&gt;
* MDL-52989 - Lesson: Fixed regression in cluster navigation&lt;br /&gt;
* MDL-61183 - Display participants count on course participants page&lt;br /&gt;
* MDL-60196 - Display custom external tool icon in activity chooser&lt;br /&gt;
* MDL-61736 - Show self enroled user as inactive when self enrolement method is disabled&lt;br /&gt;
* MDL-61800 - A bug which led to the failure of some Scheduled Tasks in certain circmstances has been fixed.&lt;br /&gt;
* MDL-61733 - Database module: Fixed bug with creating tables in templates using Atto editor&lt;br /&gt;
* MDL-61348 - Quiz: Fixed a report bug where the count of the number of attempts is sometimes incorrect in group averages&lt;br /&gt;
* MDL-61520 - Quiz: Fixed a bug where the question text was no longer exported in the quiz statistics HTML download&lt;br /&gt;
* MDL-61950 - Quiz: Fixed a bug in the statistics report to display the chosen questions for random question slots&lt;br /&gt;
* MDL-62202 - GDPR: Moved the Privacy and policies administration section to the Users tab (when GDPR plugins are installed)&lt;br /&gt;
* MDL-62042 - Global search: Remove unicode non-characters from indexing to resolve indexing errors&lt;br /&gt;
* MDL-61827 - Facebook OAuth2: Update the Facebook Graph API to v2.12&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.4.2 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.4]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.4.3]]&lt;br /&gt;
[[es:Notas de Moodle 3.4.3]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.3.5_release_notes&amp;diff=53886</id>
		<title>Moodle 3.3.5 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.3.5_release_notes&amp;diff=53886"/>
		<updated>2018-03-23T12:05:01Z</updated>

		<summary type="html">&lt;p&gt;Fox: Regression&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 19 March 2018&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.3.5%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.3.5].&lt;br /&gt;
 &lt;br /&gt;
=== Highlights ===&lt;br /&gt;
&lt;br /&gt;
* MDL-48501, MDL-61600 - Migrate to reCAPTCHA v2&lt;br /&gt;
* MDL-51189 - Quiz: now possible to edit user overrides even if quiz is not available to a student&lt;br /&gt;
* MDL-60241 - Invisible default sections lead to unexpected visibility layout&lt;br /&gt;
* MDL-61344 - Assignment: &amp;quot;additional files&amp;quot; are now shown in Edit Submission view&lt;br /&gt;
&lt;br /&gt;
=== GDPR preparation ===&lt;br /&gt;
&lt;br /&gt;
Plugins will be available for Moodle 3.3 and 3.4 to help Moodle sites to comply with GDPR. In Moodle 3.5 they will be included in the standard distribution. Some necessary core changes were already included in this release:&lt;br /&gt;
&lt;br /&gt;
* MDL-61307 - New Privacy subsystem&lt;br /&gt;
* MDL-61477 - Allow plugins to handle site policies and overwrite $CFG-&amp;gt;sitepolicy&lt;br /&gt;
* MDL-61423 - Signup process - add minimum age verification&lt;br /&gt;
&lt;br /&gt;
=== Fixes and improvements ===&lt;br /&gt;
&lt;br /&gt;
* MDL-58006 - Assignment: reset &#039;Blind marking&#039; status during &#039;Course reset&#039;&lt;br /&gt;
* MDL-58845 - Choice: hide &amp;quot;unanswered&amp;quot; column when it is set so in choice settings&lt;br /&gt;
* MDL-56688 - Single View &amp;amp; grades export should follow the same order set in gradebook set up&lt;br /&gt;
* MDL-61305 - Performance: Modinfo cache can get built in parallel&lt;br /&gt;
* MDL-61242 - EQUELLA repository: fixed error &amp;quot;The source url does not match the sourcekey.&amp;quot;&lt;br /&gt;
* MDL-61175 - Change &amp;quot;Remind me to grade by&amp;quot; date according to the new course start date after course restore&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
&lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
&lt;br /&gt;
=== Regression ===&lt;br /&gt;
&lt;br /&gt;
Regressions are problems created by the new version, that didn&#039;t exists in previous version.&lt;br /&gt;
* MDL-61723 - Courses with long &amp;quot;shortname&amp;quot; can&#039;t backup anymore&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.3.4 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.3]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.3.5]]&lt;br /&gt;
[[es:Notas de Moodle 3.3.5]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.4.2_release_notes&amp;diff=53822</id>
		<title>Moodle 3.4.2 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.4.2_release_notes&amp;diff=53822"/>
		<updated>2018-03-16T13:30:44Z</updated>

		<summary type="html">&lt;p&gt;Fox: Links corrected (wrong version)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 19 March 2018 (Not yet released)&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.4.2%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.4.2].&lt;br /&gt;
 &lt;br /&gt;
=== Highlights ===&lt;br /&gt;
&lt;br /&gt;
* MDL-48501, MDL-61600 - Migrate to reCAPTCHA v2&lt;br /&gt;
* MDL-51189 - Quiz: now possible to edit user overrides even if quiz is not available to a student&lt;br /&gt;
* MDL-60241 - Invisible default sections lead to unexpected visibility layout&lt;br /&gt;
* MDL-61344 - Assignment: &amp;quot;additional files&amp;quot; are now shown in Edit Submission view&lt;br /&gt;
&lt;br /&gt;
=== GDPR preparation ===&lt;br /&gt;
&lt;br /&gt;
Plugins will be available for Moodle 3.3 and 3.4 to help Moodle sites to comply with GDPR. In Moodle 3.5 they will be included in the standard distribution. Some necessary core changes were already included in this release:&lt;br /&gt;
&lt;br /&gt;
* MDL-61307 - New Privacy subsystem&lt;br /&gt;
* MDL-61477 - Allow plugins to handle site policies and overwrite $CFG-&amp;gt;sitepolicy&lt;br /&gt;
* MDL-61423 - Signup process - add minimum age verification&lt;br /&gt;
&lt;br /&gt;
=== Fixes and improvements ===&lt;br /&gt;
&lt;br /&gt;
* MDL-60815 - Fixed bug with loading CSS for editor&lt;br /&gt;
* MDL-61549 - Fixed bug with empty user name on Participants page if username is included in user identitfy fields&lt;br /&gt;
* MDL-60812 - Select correct default role during manual enrolment&lt;br /&gt;
* MDL-58006 - Assignment: reset &#039;Blind marking&#039; status during &#039;Course reset&#039;&lt;br /&gt;
* MDL-58845 - Choice: hide &amp;quot;unanswered&amp;quot; column when it is set so in choice settings&lt;br /&gt;
* MDL-56688 - Single View &amp;amp; grades export should follow the same order set in gradebook set up&lt;br /&gt;
* MDL-61305 - Performance: Modinfo cache can get built in parallel&lt;br /&gt;
* MDL-61249 - Corrected end date for manual enrolments&lt;br /&gt;
* MDL-61242 - EQUELLA repository: fixed error &amp;quot;The source url does not match the sourcekey.&amp;quot;&lt;br /&gt;
* MDL-61175 - Change &amp;quot;Remind me to grade by&amp;quot; date according to the new course start date after course restore&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
A number of security related issues were resolved. Details of these issues will be released after a period of approximately one week to allow system administrators to safely update to the latest version.&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.4.1 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.4]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.4.2]]&lt;br /&gt;
[[es:Notas de Moodle 3.4.2]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.5&amp;diff=53504</id>
		<title>Category:Moodle 3.5</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Category:Moodle_3.5&amp;diff=53504"/>
		<updated>2017-12-12T08:59:44Z</updated>

		<summary type="html">&lt;p&gt;Fox: Creation of the category page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Pages that relate to the planning and development of Moodle 3.5 features.&lt;br /&gt;
&lt;br /&gt;
[[fr:Catégorie:Moodle 3.5]]&lt;/div&gt;</summary>
		<author><name>Fox</name></author>
	</entry>
</feed>