<?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=Dougiamas</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=Dougiamas"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Dougiamas"/>
	<updated>2026-07-15T17:28:15Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=63945</id>
		<title>MoodleNet</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=63945"/>
		<updated>2023-07-20T09:37:47Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* What is MoodleNet? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Moodlenet-logo.png|400px]]&lt;br /&gt;
== What is MoodleNet? ==&lt;br /&gt;
[https://moodle.net/ MoodleNet] is a flexible Open Education Technology platform for curating collections of the best known Open Educational (and other) Resources. You&#039;ll find more general information in the [https://docs.moodle.org/moodlenet/Main_Page MoodleNet user documentation].&lt;br /&gt;
&lt;br /&gt;
If you are looking to get started as a MoodleNet developer, we have some courses on Moodle Academy.  Both are a bit old but will be updated soon.&lt;br /&gt;
&lt;br /&gt;
* [https://moodle.academy/course/view.php?id=13# Introduction to MoodleNet] &lt;br /&gt;
* [https://moodle.academy/course/view.php?id=74 MoodleNet for Developers course with Moodle Academy] &lt;br /&gt;
&lt;br /&gt;
== Current status ==&lt;br /&gt;
We have just released MoodleNet 3.0.   You can follow the releases on Moodle&#039;s Jira tracker at [https://tracker.moodle.org/projects/MDLNET?selectedItem=com.atlassian.jira.jira-projects-plugin%3Arelease-page&amp;amp;status=unreleased MDLNET]. &lt;br /&gt;
== Roadmap ==&lt;br /&gt;
See [https://tracker.moodle.org/secure/RapidBoard.jspa?rapidView=120&amp;amp;projectKey=MDLNET&amp;amp;view=detail our work on new features in the tracker].&lt;br /&gt;
&lt;br /&gt;
== Quick start guide ==&lt;br /&gt;
====System Requirements====&lt;br /&gt;
To install MoodleNet, we recommend using the following on your system:&lt;br /&gt;
*[https://nodejs.org NodeJS] 16 &lt;br /&gt;
*[https://nodejs.org/en/knowledge/getting-started/npm/what-is-npm/ npm] 8&lt;br /&gt;
*[https://www.arangodb.com/ ArangoDB] 3.10&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Later versions should probably work but have not been tested yet.&lt;br /&gt;
====Deploy an ArangoDB instance====&lt;br /&gt;
MoodleNet uses [https://www.arangodb.com/ ArangoDB] as main database&lt;br /&gt;
&lt;br /&gt;
You can choose how and where to deploy your ArangoDB, as long as it can be reached by MoodleNet process&lt;br /&gt;
&lt;br /&gt;
An easy way to install run ArangDB locally as a service is by using Docker[https://hub.docker.com/_/arangodb] e.g. :&lt;br /&gt;
 docker run -d --restart unless-stopped -e ARANGO_NO_AUTH=1 -p 8529:8529 --name=mn-3-db arangodb:3.10&lt;br /&gt;
Possibly tweaking some options as you like, e.g. mounting a volume|directory for data or setting a password&lt;br /&gt;
====Install MoodleNet ====&lt;br /&gt;
Install Moodlenet by simply issuing the following npm command&lt;br /&gt;
 npm create @moodlenet@latest path/to/installation/folder&lt;br /&gt;
That will install all MoodleNet core packages in the chosen folder&lt;br /&gt;
&lt;br /&gt;
it will also create a default configuration file (&#039;&#039;&#039;default.config.json&#039;&#039;&#039;) and a default cryptographic key-pair for the system (&#039;&#039;&#039;default.crypto.privateKey , default.crypto.publicKey&#039;&#039;&#039;)&lt;br /&gt;
====Start MoodleNet process ====&lt;br /&gt;
To start MoodleNet issue the following command from within the installation directory&lt;br /&gt;
 npm start&lt;br /&gt;
open your browser on http://localhost:8080&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Notice:&#039;&#039;&#039; on the first run the system will have to compile the webapp, so you&#039;ll get a 404 until ready. It should take a few minutes.&lt;br /&gt;
====MoodleNet configuration file====&lt;br /&gt;
MoodleNet configuration file (&#039;&#039;&#039;default.config.json&#039;&#039;&#039;) holds all static system configs.&lt;br /&gt;
&lt;br /&gt;
Here&#039;s how the default config looks like after install:&lt;br /&gt;
 {&lt;br /&gt;
   &amp;quot;pkgs&amp;quot;: {&lt;br /&gt;
     &amp;quot;@moodlenet/core&amp;quot;: {&lt;br /&gt;
       &amp;quot;baseFsFolder&amp;quot;: &amp;quot;/path/to/installation/dir/fs&amp;quot;,&lt;br /&gt;
       &amp;quot;instanceDomain&amp;quot;: &amp;quot;&amp;lt;nowiki&amp;gt;http://localhost:8080&amp;lt;/nowiki&amp;gt;&amp;quot;,&lt;br /&gt;
       &amp;quot;npmRegistry&amp;quot;: &amp;quot;&amp;lt;nowiki&amp;gt;https://registry.npmjs.org&amp;lt;/nowiki&amp;gt;&amp;quot;,&lt;br /&gt;
       &amp;quot;mainLogger&amp;quot;: {&lt;br /&gt;
         &amp;quot;consoleLevel&amp;quot;: &amp;quot;info&amp;quot;,&lt;br /&gt;
         &amp;quot;file&amp;quot;: {&lt;br /&gt;
           &amp;quot;path&amp;quot;: &amp;quot;./log/moodlenet.%DATE%.log&amp;quot;,&lt;br /&gt;
           &amp;quot;level&amp;quot;: &amp;quot;info&amp;quot;&lt;br /&gt;
         }&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/crypto&amp;quot;: {&lt;br /&gt;
       &amp;quot;keys&amp;quot;: {&lt;br /&gt;
         &amp;quot;alg&amp;quot;: &amp;quot;RS256&amp;quot;,&lt;br /&gt;
         &amp;quot;type&amp;quot;: &amp;quot;PKCS8&amp;quot;,&lt;br /&gt;
         &amp;quot;private&amp;quot;: &amp;quot;/path/to/installation/dir/default.crypto.privateKey&amp;quot;,&lt;br /&gt;
         &amp;quot;public&amp;quot;: &amp;quot;/path/to/installation/dir/default.crypto.publicKey&amp;quot;&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/arangodb&amp;quot;: {&lt;br /&gt;
       &amp;quot;connectionCfg&amp;quot;: {&lt;br /&gt;
         &amp;quot;url&amp;quot;: &amp;quot;&amp;lt;nowiki&amp;gt;http://localhost:8529&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/http-server&amp;quot;: {&lt;br /&gt;
       &amp;quot;port&amp;quot;: 8080,&lt;br /&gt;
       &amp;quot;defaultRpcUploadMaxSize&amp;quot;: &amp;quot;5MB&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/ed-resource&amp;quot;: {&lt;br /&gt;
       &amp;quot;resourceUploadMaxSize&amp;quot;: &amp;quot;1.2GB&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/simple-email-auth&amp;quot;: {&lt;br /&gt;
       &amp;quot;newUserNotPublisher&amp;quot;: false&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/email-service&amp;quot;: {&lt;br /&gt;
       &amp;quot;nodemailerTransport&amp;quot;: {&lt;br /&gt;
         &amp;quot;jsonTransport&amp;quot;: true&lt;br /&gt;
       }&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/system-entities&amp;quot;: {&lt;br /&gt;
       &amp;quot;rootPassword&amp;quot;: &amp;quot;eqhb30x9iq5&amp;quot;&lt;br /&gt;
     },&lt;br /&gt;
     &amp;quot;@moodlenet/react-app&amp;quot;: {}&lt;br /&gt;
   }&lt;br /&gt;
Here are some relevant configs you may want to check and tweak:&lt;br /&gt;
*&#039;&#039;&#039;@moodlenet/arangodb.connectionCfg.url&#039;&#039;&#039; : the default config assumes you installed ArangoDB without password with standard port on the same host&lt;br /&gt;
*&#039;&#039;&#039;@moodlenet/core.baseFsFolder&#039;&#039;&#039; : path (better absolute path instead of relative to MoodleNet process cwd) to the system root folder for system filesystem persistency, if you want to change the system-filesystem-root after the system already run, move or clone the existing folder somewhere else and set this config properly to point to the new path&lt;br /&gt;
*&#039;&#039;&#039;@moodlenet/core.instanceDomain&#039;&#039;&#039; : the public domain of your moodlenet instance (e.g. &amp;lt;nowiki&amp;gt;https://moodlenet.example.com&amp;lt;/nowiki&amp;gt;) - the default one (&amp;lt;nowiki&amp;gt;http://localhost:8080&amp;lt;/nowiki&amp;gt;) is ok for testing and dev&lt;br /&gt;
*&#039;&#039;&#039;@moodlenet/email-service.nodemailerTransport&#039;&#039;&#039; : the [https://nodemailer.com/ nodemailer] [https://nodemailer.com/smtp/ transport configuration] for the system email service. It can be a simple smtp url string, or a [https://nodemailer.com/smtp/ nodemailer standard config object]. &#039;&#039;&#039;Notice&#039;&#039;&#039;: with the default configuration &#039;&#039;&#039;{ &amp;quot;jsonTransport&amp;quot;: true }&#039;&#039;&#039; the system won&#039;t send any email, it will simply log them)&lt;br /&gt;
*&#039;&#039;&#039;@moodlenet/system-entities.rootPassword&#039;&#039;&#039; : a static root password for edge cases - you&#039;ll use it to give the first admin permission to a user (see below) - this property is optional, if not set the root user is disabled&lt;br /&gt;
*&#039;&#039;&#039;@moodlenet/http-server.port&#039;&#039;&#039; : the HTTP server port to listen&lt;br /&gt;
 &lt;br /&gt;
Moodlenet&#039;s HTTP service doesn&#039;t support HTTPS. &lt;br /&gt;
&lt;br /&gt;
It&#039;s always a good practice to back Moodlenet with a HTTP reverse proxy (e.g. nginx, Apache) and it is a must if you want to publish over HTTPS, configuring TLS on it.&lt;br /&gt;
====Default authentication system====&lt;br /&gt;
Moodlenet comes with a simple email+password authentication system (pkg @moodlenet/simple-email-auth) that lets users signup and login with a verified email&lt;br /&gt;
&lt;br /&gt;
Users can sign up with their email, receive in their inbox a confirmation link to click and create their user-account&lt;br /&gt;
====Assign admin privileges to your user====&lt;br /&gt;
As you deploy a new instance, no user is present in the system. &lt;br /&gt;
&lt;br /&gt;
Signup with your email and create your user.&lt;br /&gt;
&lt;br /&gt;
Test login, then logout and browse to the hidden page &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;http://localhost:8080/login/root&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;, here you can type in the &#039;&#039;&#039;rootPassword&#039;&#039;&#039; (specified in config file) to login as root.&lt;br /&gt;
&lt;br /&gt;
Open the avatar menu on top right header, and click &#039;&#039;&#039;admin&#039;&#039;&#039; link&lt;br /&gt;
&lt;br /&gt;
Click on &#039;&#039;&#039;Users&#039;&#039;&#039; section on the left, and see your user listed there. Activate the &#039;&#039;&#039;admin&#039;&#039;&#039; icon to give yourself admin privileges&lt;br /&gt;
&lt;br /&gt;
Now you can log out and login back with your email, see you gained the &#039;&#039;&#039;admin&#039;&#039;&#039; link in your avatar menu&lt;br /&gt;
&lt;br /&gt;
Admins can directly use that admin page feature anytime to assign and remove admin privileges to other users&lt;br /&gt;
== Update the system==&lt;br /&gt;
You can easily upgrade MoodleNet keeping system packages always up-to-date with the minor and patch releases by issuing the command&lt;br /&gt;
 npm update&lt;br /&gt;
from within the installation directory, the same where you start the system&lt;br /&gt;
&lt;br /&gt;
Since MoodleNet is npm-package based, it leverages all npm features for upgrades and new packages installation&lt;br /&gt;
== Migrate from V2==&lt;br /&gt;
If you have a v2 running and want to migrate it to v3 , you can use the [https://www.npmjs.com/package/@moodlenet/v2-migrate-v3 @moodlenet/v2-migrate-v3]&lt;br /&gt;
&lt;br /&gt;
The v3 system must have access to Moodlenet-V2 persistencies: its running arangoDB instance and the MN2 filesystem as configured in [https://gitlab.com/moodlenet/moodlenet/-/tree/1c8c7eb9b9aa2a3ee912871c670480b3e5fa0f70/packages/ce-platform#set-environment-variables V2 env variable &#039;&#039;&#039;STATICASSETS_FS_ROOT_FOLDER&#039;&#039;&#039;]&lt;br /&gt;
&lt;br /&gt;
After Moodlenet v3 is installed (as above), issue the following command from the installation folder&lt;br /&gt;
 npm install @moodlenet/v2-migrate-v3&lt;br /&gt;
Edit the &#039;&#039;&#039;default.config.json&#039;&#039;&#039; adding a &#039;&#039;&#039;@moodlenet/v2-migrate-v3&#039;&#039;&#039; section beside the others, it should look like that&lt;br /&gt;
     &amp;quot;@moodlenet/v2-migrate-v3&amp;quot;: {&lt;br /&gt;
       &amp;quot;v2DbConnectionCfg&amp;quot;: {&lt;br /&gt;
         &amp;quot;url&amp;quot;: &amp;quot;&amp;lt;nowiki&amp;gt;http://your-mn-v2-arangodb-host:8529&amp;lt;/nowiki&amp;gt;&amp;quot;&lt;br /&gt;
       },&lt;br /&gt;
       &amp;quot;v2AssetFolder&amp;quot;: &amp;quot;/path/to/v2/asset/folder&amp;quot;&lt;br /&gt;
     }&lt;br /&gt;
Then just restart the system, the migration will be done, services will be restarted and you can log in.&lt;br /&gt;
&lt;br /&gt;
This migration package can be deleted now if you would like.&lt;br /&gt;
==MoodleNet architecture==&lt;br /&gt;
MoodleNet is a full stack TypeScript/JavaScript system using:&lt;br /&gt;
*NodeJs&lt;br /&gt;
**NPM Packages [https://nodejs.org/en/knowledge/getting-started/npm/what-is-npm/]&lt;br /&gt;
**ESM Modules [https://nodejs.org/api/esm.html#introduction]&lt;br /&gt;
*Browsers&lt;br /&gt;
**ReactJs 18 [https://reactjs.org/]&lt;br /&gt;
**HTML5 [https://html.spec.whatwg.org/multipage/]&lt;br /&gt;
**CSS3 [https://www.w3.org/Style/CSS/]&lt;br /&gt;
==MoodleNet development environment ==&lt;br /&gt;
*NodeJs ^16 https://nodejs.org/&lt;br /&gt;
*ArangoDB ^3 (we suggest using [https://www.docker.com/ Docker])&lt;br /&gt;
* We recommend the open source IDE Visual Studio Code https://code.visualstudio.com/&lt;br /&gt;
===Setup development environment ===&lt;br /&gt;
&#039;&#039;&#039;From the command line interface (CLI):&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Ensure ArangoDB is running on localhost. You may run it in a Docker container issuing a command as below:&lt;br /&gt;
 docker run -e ARANGO_NO_AUTH=1 -p 8529:8529 --name=mn3-dev arangodb:3.10&lt;br /&gt;
Clone the repository, you may wish to fork it, but that&#039;s not required:&lt;br /&gt;
 git clone &amp;lt;nowiki&amp;gt;https://gitlab.com/moodlenet/moodlenet.git&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
Change to the project&#039;s folder:&lt;br /&gt;
 cd moodlenet&lt;br /&gt;
Install and initialise the project:&lt;br /&gt;
 npm install&lt;br /&gt;
Install a development server:&lt;br /&gt;
 npm run dev-install-backend my-dev # &amp;lt;- my-dev: an arbitrary dev-installation name&lt;br /&gt;
In the example we chose &#039;&#039;&#039;my-dev&#039;&#039;&#039; as installation name, the tool will then setup a dev installation in &#039;&#039;&#039;./.dev-machines/my-dev&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You can create as many dev installations as you wish.&lt;br /&gt;
&lt;br /&gt;
Run development backend:&lt;br /&gt;
 npm run dev-start-backend my-dev # &amp;lt;- my-dev : the name you chose when installed&lt;br /&gt;
The first run of the system may take some time to install.&lt;br /&gt;
&lt;br /&gt;
The default configuration for dev includes the config &#039;&#039;&#039;@moodlenet/react-app.noWebappServer: true&#039;&#039;&#039; that prevents the server to serve the webapp, so you won&#039;t access the webapp on &amp;lt;nowiki&amp;gt;http://localhost:8080&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Instead, you&#039;ll want to run a webpack+HMR serving the webapp issuing&lt;br /&gt;
 npm run dev-start-webapp my-dev # &amp;lt;- my-dev: the installation server to point to&lt;br /&gt;
Once all started, browse http://localhost:3000&lt;br /&gt;
=== Mono-Repository management with Lerna.js===&lt;br /&gt;
MoodleNet project takes leverages [https://lerna.js.org/ lerna.js] to manage multi-package mono-repository .&lt;br /&gt;
&lt;br /&gt;
Please refer to [https://lerna.js.org/ Lerna documentation] to understand how it manages mono-repo and project-packages dependency linking in the development environment.&lt;br /&gt;
&lt;br /&gt;
Questions? Please take a look in the [https://moodle.org/mod/forum/view.php?id=8726 MoodleNet Community] and [https://tracker.moodle.org/projects/MDLNET/summary Tracker] for answers or to ask for help.&lt;br /&gt;
*[https://moodledev.io/general/development/tracker Using Tracker]&lt;br /&gt;
*[https://www.npmjs.com/package/@moodlenet/ce-platform Code repository]&lt;br /&gt;
*[https://docs.moodle.org/moodlenet/Main_Page MoodleNet user documentation]&lt;br /&gt;
*[https://moodle.org/mod/forum/view.php?id=8726 MoodleNet news and discussion]&lt;br /&gt;
*[https://tracker.moodle.org/secure/RapidBoard.jspa?rapidView=167&amp;amp;view=detail MoodleNet Issue Tracker]&lt;br /&gt;
*[https://gitlab.com/moodlenet/moodlenet/-/issues MoodleNet Gitlab Issues]&lt;br /&gt;
[[es:MoodleNet]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58991</id>
		<title>MoodleNet</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58991"/>
		<updated>2021-06-21T13:08:25Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* Important links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Moodlenet-logo.png|400px]]&lt;br /&gt;
&lt;br /&gt;
== What is MoodleNet? ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is our new social network to share and curate open educational resources with educators world-wide.  It is integrated closely with Moodle LMS and Moodle Workplace to make resources easy to find and use, but can be useful even if you don&#039;t use Moodle LMS. MoodleNet is also intended as a way to build your profile as an educator.&lt;br /&gt;
&lt;br /&gt;
Importantly, MoodleNet is designed to be a federated, flexible Open Education Technology that is not controlled by a single entity, or subject to a single point of failure.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Current status ==&lt;br /&gt;
&#039;&#039;Last updated: 31 May 2021&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet 1.x was abandoned by the team in 2021 because it was heading down the wrong path.  The project was recently rebooted (January 2021) with a new team, new architecture and a simpler new design.&lt;br /&gt;
&lt;br /&gt;
== Roadmap ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;15 August 2021&#039;&#039;&#039; - MVP for wider community testing and feedback&lt;br /&gt;
* &#039;&#039;&#039;31 August 2021&#039;&#039;&#039; - Beta release , feature complete for 2.0 release.&lt;br /&gt;
* &#039;&#039;&#039;15 September 2021&#039;&#039;&#039; - 2.0 release!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Important links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitlab.com/moodlenet Code repository]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=8726 MoodleNet news and discussion]&lt;br /&gt;
* [https://tracker.moodle.org/secure/RapidBoard.jspa?rapidView=167&amp;amp;view=detail MoodleNet Issue Tracker]&lt;br /&gt;
&lt;br /&gt;
== Archive ==&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/research Research]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Copyright_Directive European Copyright Directive]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/DPIA Data Protection Impact Assessment]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:MoodleNet]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58936</id>
		<title>MoodleNet</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58936"/>
		<updated>2021-05-31T12:47:10Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* Archive */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Moodlenet-logo.png|400px]]&lt;br /&gt;
&lt;br /&gt;
== What is MoodleNet? ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is our new social network to share and curate open educational resources with educators world-wide.  It is integrated closely with Moodle LMS and Moodle Workplace to make resources easy to find and use, but can be useful even if you don&#039;t use Moodle LMS. MoodleNet is also intended as a way to build your profile as an educator.&lt;br /&gt;
&lt;br /&gt;
Importantly, MoodleNet is designed to be a federated, flexible Open Education Technology that is not controlled by a single entity, or subject to a single point of failure.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Current status ==&lt;br /&gt;
&#039;&#039;Last updated: 31 May 2021&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet 1.x was abandoned by the team in 2021 because it was heading down the wrong path.  The project was recently rebooted (January 2021) with a new team, new architecture and a simpler new design.&lt;br /&gt;
&lt;br /&gt;
== Roadmap ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;15 August 2021&#039;&#039;&#039; - MVP for wider community testing and feedback&lt;br /&gt;
* &#039;&#039;&#039;31 August 2021&#039;&#039;&#039; - Beta release , feature complete for 2.0 release.&lt;br /&gt;
* &#039;&#039;&#039;15 September 2021&#039;&#039;&#039; - 2.0 release!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Important links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitlab.com/moodlenet Code repository]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=8726 MoodleNet news and discussion]&lt;br /&gt;
&lt;br /&gt;
== Archive ==&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/research Research]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Copyright_Directive European Copyright Directive]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/DPIA Data Protection Impact Assessment]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:MoodleNet]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/research&amp;diff=58935</id>
		<title>MoodleNet/research</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/research&amp;diff=58935"/>
		<updated>2021-05-31T12:46:48Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
=== Other similar systems ===&lt;br /&gt;
&lt;br /&gt;
See [[MoodleNet/research/other]]&lt;br /&gt;
&lt;br /&gt;
=== DMCA ===&lt;br /&gt;
&lt;br /&gt;
From [https://en.wikipedia.org/wiki/Digital_Millennium_Copyright_Act Wikipedia]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;The Digital Millennium Copyright Act (DMCA) is a 1998 United States copyright law that implements two 1996 treaties of the World Intellectual Property Organization (WIPO). It criminalizes production and dissemination of technology, devices, or services intended to circumvent measures that control access to copyrighted works (commonly known as digital rights management or DRM). It also criminalizes the act of circumventing an access control, whether or not there is actual infringement of copyright itself. In addition, the DMCA heightens the penalties for copyright infringement on the Internet.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;DMCA Title II, the Online Copyright Infringement Liability Limitation Act (&amp;quot;OCILLA&amp;quot;), creates a safe harbor for online service providers (OSPs, including ISPs) against copyright infringement liability, provided they meet specific requirements. OSPs must adhere to and qualify for certain prescribed safe harbor guidelines and promptly block access to alleged infringing material (or remove such material from their systems) when they receive notification of an infringement claim from a copyright holder or the copyright holder&#039;s agent. OCILLA also includes a counternotification provision that offers OSPs a safe harbor from liability to their users when users claim that the material in question is not, in fact, infringing. OCILLA also facilitates issuing of subpoenas against OSPs to provide their users&#039; identity.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Social networks integrating &#039;currency&#039; ===&lt;br /&gt;
&lt;br /&gt;
* [https://memo.cash/ Memo]&lt;br /&gt;
* [https://www.minds.com/ Minds]&lt;br /&gt;
* [https://steemit.com/ Steemit]&lt;br /&gt;
* [https://tri.cash/ Trillion]&lt;br /&gt;
* [http://www.yy.com/ YY.com] &#039;&#039;(Chinese)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== DPIA ===&lt;br /&gt;
&lt;br /&gt;
A [https://ico.org.uk/for-organisations/guide-to-the-general-data-protection-regulation-gdpr/data-protection-impact-assessments-dpias/what-is-a-dpia/ Data Protection Impact Assessment] &amp;quot;is a process designed to help you systematically analyse, identify and minimise the data protection risks of a project or plan&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
We need to decide whether MoodleNet meets any of the three criteria which would necessitate a DPIA:&lt;br /&gt;
&lt;br /&gt;
# Systematic and extensive profiling with significant effects&lt;br /&gt;
# Large scale use of sensitive data&lt;br /&gt;
# Public monitoring&lt;br /&gt;
&lt;br /&gt;
It may be a good idea to create a DPIA in any case, as part of our GDPR compliance.&lt;br /&gt;
&lt;br /&gt;
=== Translation platforms ===&lt;br /&gt;
&lt;br /&gt;
* [https://www.applanga.com/ Applanga]&lt;br /&gt;
* [https://crowdin.com Crowdin]&lt;br /&gt;
* [https://www.memoq.com/en/memoq-translator-free memoq]&lt;br /&gt;
* [https://poeditor.com/ POEditor]&lt;br /&gt;
* [http://pootle.translatehouse.org/index.html Pootle]&lt;br /&gt;
* [https://www.textunited.com/ TextUnited]&lt;br /&gt;
* [https://www.transifex.com/ Transifex]&lt;br /&gt;
* [http://zanata.org/ Zanata]&lt;br /&gt;
&lt;br /&gt;
=== Accessibility ===&lt;br /&gt;
&lt;br /&gt;
* [https://accessibility.blog.gov.uk/ Gov.uk accessibility]&lt;br /&gt;
* [https://www.marcozehe.de/2015/12/14/the-web-accessibility-basics/ Marco&#039;s accessibility blog]&lt;br /&gt;
* [https://www.usability.gov/what-and-why/accessibility.html Usability.gov]&lt;br /&gt;
* [https://www.w3.org/wiki/Accessibility_basics W3C Accessibility basics]&lt;br /&gt;
* [https://www.w3.org/WAI/standards-guidelines/wcag/glance/ Web Content Accessibility Guidelines (WCAG) 2.1]&lt;br /&gt;
* [https://wordpress.org/about/accessibility/ WordPress accessibility]&lt;br /&gt;
&lt;br /&gt;
=== Policy docs from other federated systems ===&lt;br /&gt;
&lt;br /&gt;
[https://the-federation.info/ Federated systems] tend to have a website explaining the service, then link to specific instances. As the terms of service, privacy policy, etc. may differ greatly from instance to instance, the list below takes a popular example of the service.&lt;br /&gt;
&lt;br /&gt;
* [https://diasporafoundation.org/ Diaspora]&lt;br /&gt;
** [https://diasp.org Diasp.org] &lt;br /&gt;
*** [https://diasp.org/terms Terms of service and privacy policy]&lt;br /&gt;
* [https://friendi.ca/ Friendica]&lt;br /&gt;
** [https://libranet.de/ Libranet.de]&lt;br /&gt;
*** [https://libranet.de/friendica Terms of use, data protection and data security] (in German)&lt;br /&gt;
* [https://gnu.io/social/ GNU social]&lt;br /&gt;
** [https://status.pirati.ca Piratica]&lt;br /&gt;
*** [https://status.pirati.ca/doc/privacy Privacy policy]&lt;br /&gt;
* [https://project.hubzilla.org/ Hubzilla]&lt;br /&gt;
** [https://start.hubzilla.org Start.hubzilla.org]&lt;br /&gt;
*** [https://start.hubzilla.org/help/en-gb/TermsOfService Terms of service]&lt;br /&gt;
* [https://joinmastodon.org/ Mastodon]&lt;br /&gt;
** [https://mastodon.social/about Mastodon.social]&lt;br /&gt;
*** [https://mastodon.social/about/more Code of conduct]&lt;br /&gt;
*** [https://mastodon.social/terms Privacy policy]&lt;br /&gt;
* [https://joinmisskey.github.io/en/ Misskey]&lt;br /&gt;
** [https://tri.cash/ Trillion]&lt;br /&gt;
*** [https://tri.cash/news/wp/terms/ Terms of service] &#039;&#039;(note: also uses e-currency)&#039;&#039;&lt;br /&gt;
* [https://zotlabs.com/osada/ Osada]&lt;br /&gt;
** [https://osada.gibberfish.org Osada.gibberfish.org]&lt;br /&gt;
*** [https://osada.gibberfish.org/help/en-gb/TermsOfService Terms of service] &#039;&#039;(essentially the same as Hubzilla)&#039;&#039;&lt;br /&gt;
* [https://joinpeertube.org/en/ PeerTube]&lt;br /&gt;
** [https://pe.ertu.be/ Pe.ertu.be]&lt;br /&gt;
*** [https://pe.ertu.be/about/instance About and terms]&lt;br /&gt;
* [https://pixelfed.org/ PixelFed]&lt;br /&gt;
** [https://pixelfed.social/ Pixelfed.social]&lt;br /&gt;
*** [https://pixelfed.social/site/terms Terms of use]&lt;br /&gt;
*** [https://pixelfed.social/site/privacy Privacy policy]&lt;br /&gt;
* [https://pleroma.social Pleroma]&lt;br /&gt;
** [https://pleroma.site Pleroma.site]&lt;br /&gt;
*** [https://info.pleroma.site/tos.html Terms of service]&lt;br /&gt;
*** [https://info.pleroma.site/ Site info] (include warrant canary, hardware specs, etc.)&lt;br /&gt;
*** [https://info.pleroma.site/federation.html Federation policy]&lt;br /&gt;
*** [https://info.pleroma.site/privacy.html Privacy policy]&lt;br /&gt;
* [https://plume-org.github.io/Plume/ Plume]&lt;br /&gt;
** [https://fediverse.blog Fediverse.blog]&lt;br /&gt;
*** [https://fediverse.blog/about About]&lt;br /&gt;
&lt;br /&gt;
=== Authentication systems ===&lt;br /&gt;
&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Mozilla_Persona Mozilla Persona] (decommissioned, but useful info in project - including [https://web.archive.org/web/20140713180852/http://lloyd.io/how-browserid-works this post])&lt;br /&gt;
* [https://en.wikipedia.org/wiki/OAuth OAuth]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/OpenID OpenID]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language SAML]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/WebID WebID]&lt;br /&gt;
&lt;br /&gt;
=== Interesting projects, products, and standards ===&lt;br /&gt;
&lt;br /&gt;
* [https://activitypub.rocks/ ActivityPub] - a &amp;quot;decentralized social networking protocol based upon the ActivityStreams 2.0 data format. It provides a client to server API for creating, updating and deleting content, as well as a federated server to server API for delivering notifications and content&amp;quot;. Useful comments and caveats in [https://news.ycombinator.com/item?id=14417315 this Hacker News thread]. The [https://www.w3.org/TR/activitypub/ spec] (latest version: Nov 2017) is well-written.&lt;br /&gt;
* [https://beakerbrowser.com Beaker] - a peer-to-peer browser with tools to create and host websites.&lt;br /&gt;
* [https://www.bigchaindb.com BigchainDB] - a decentralised open-source database with blockchain data structure to enhance scalability, write and read speed, and data extraction capability.&lt;br /&gt;
* [https://blockstack.org Blockstack] - a new network for decentralised applications, including an alternate DNS and public-key infrastructure.&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cooperative_storage_cloud Co-operative Storage Cloud] - a &amp;quot;decentralized model of networked online storage where data is stored on multiple computers (nodes), hosted by the participants cooperating in the cloud&amp;quot;. &lt;br /&gt;
* [https://cryptosphere.io Cryptosphere] - an &amp;quot;open-source P2P web application platform for decentralized, privacy-preserving software which keeps users in control of their own content&amp;quot;. Defunct?&lt;br /&gt;
* [https://datproject.org Dat] - a &amp;quot;data distribution tool with a version control feature for tracking changes and publishing datasets&amp;quot;. Funded by major donors such as the Knight Foundation and Alfred P. Sloan Foundation.&lt;br /&gt;
* [https://diasporafoundation.org Diaspora] - a &amp;quot;nonprofit, user-owned, distributed social network&amp;quot; consisting of &amp;quot;independently owned nodes (called pods) which interoperate to form the network&amp;quot;.&lt;br /&gt;
* [https://edmodo.com Edmodo] - the app &amp;quot;is probably the closest thing to MoodleNet that exists&amp;quot; according to Martin Dougiamas.&lt;br /&gt;
* [https://ethereum.org Ethereum] - a &amp;quot;decentralized platform that runs smart contracts: applications that run exactly as programmed without any possibility of downtime, censorship, fraud or third party interference&amp;quot;.&lt;br /&gt;
* [https://filecoin.io Filecoin] - an &amp;quot;open-source, public, cryptocurrency and digital payment system intended to be a blockchain-based digital storage and data retrieval method&amp;quot; building on top of IPFS.&lt;br /&gt;
* [https://freenetproject.org Freenet] - a somewhat notorious peer-to-peer platform using the &#039;dark web&#039; for censorship-resistant communication. &#039;Freesites&#039; contains only static content, meaning it cannot provide content that requires a database or server-side scripts.&lt;br /&gt;
* [http://friendi.ca Friendica] - &amp;quot;open source software for a distributed social network&amp;quot; focusing on &amp;quot;effective privacy settings and easy installation of personal servers&amp;quot;. Also allows other social networks and blogs to be integrated.&lt;br /&gt;
* [https://gnunet.org GNUnet] - an &amp;quot;alternative ne twork stack for building secure, decentralized and privacy-preserving distributed applications&amp;quot;. The framework features &amp;quot;link encryption, peer discovery, resource allocation, communication over many transports (such as TCP, UDP, HTTP, HTTPS, WLAN and Bluetooth) and various basic peer-to-peer algorithms for routing, multicast and network size estimation&amp;quot;.&lt;br /&gt;
* [https://gnu.io/social GNU social] - &amp;quot;social communication software for both public and private communications&amp;quot; -  &amp;quot;widely supported and has a large userbase&amp;quot;.&lt;br /&gt;
* [https://project.hubzilla.org Hubzilla] - a &amp;quot;powerful platform for creating interconnected websites featuring a decentralized identity, communications, and permissions framework built using common webserver technology&amp;quot;.&lt;br /&gt;
* [https://geti2p.net/en I2P] - a network that provides &amp;quot;strong privacy protections for communication over the Internet&amp;quot;. Used for serverless email, anonymous websites, gateways to/from the public internet, blogging, forums, realtime chat, filesharing, decentralised file storage, and more.&lt;br /&gt;
* [https://ipdb.io IPDB] - stands for &#039;InterPlanetary DataBase&#039;, a &amp;quot;blockchain database network for the decentralized stack&amp;quot;. It&#039;s ready to use, with strong governance (including many large non-profits).&lt;br /&gt;
* [https://ipfs.io IPFS] - stands for &#039;InterPlanetary File System&#039;, a protocol &amp;quot;designed to create a permanent and decentralized method of storing and sharing files&amp;quot;. Content-addressable, peer-to-peer, distributed file system. Provides a resilient way to serve files, removing duplication and centralisation.&lt;br /&gt;
* [https://github.com/oduwsdl/ipwb IPWB] - stands for &#039;InterPlanetary WayBack&#039; and &amp;quot;facilitates permanence and collaboration in web archives&amp;quot;.&lt;br /&gt;
* [https://www.gitbook.com/book/jedisct1/libsodium/details Libsodium] - the Sodium crypto library is &amp;quot;a modern, easy-to-use software library for encryption, decryption, signatures, password hashing and more&amp;quot;.&lt;br /&gt;
* [http://www.imsglobal.org/activity/learning-tools-interoperability LTI] - stands for Learning Tools Interoperability, a standard developed by IMS Global Learning Consortium. Main use case is to enable web apps, tools or content to connect seamlessly and securely with digital learning environments.&lt;br /&gt;
* [http://www.imsglobal.org/activity/learning-tools-interoperability LTI Advantage] - a new package of extensions to the Learning Tools Interoperability standard that currently includes: Assignment and Grade Services, Deep Linking, and Names and Role Provisioning Service. Allows for better two-way sharing of data between digital learning environments and other apps/services.&lt;br /&gt;
* [https://maidsafe.net Maidsafe] - bills itself as &amp;quot;the world&#039;s first autonomous data network&amp;quot;. Reliant on cryptocurrency, but not blockchain, for network services.&lt;br /&gt;
* [https://joinmastodon.org Mastodon] - a federated social network similar to Twitter, &amp;quot;but administrated as a decentralized federation of independently operated servers running open source software&amp;quot;. Users join a specific instance, and their updates can then be federated to other instances. Mastodon is built on OStatus, meaning that federated Mastodon instances form just one part of a wider &#039;Fediverse&#039;.&lt;br /&gt;
* [https://matrix.org Matrix] - an &amp;quot;open protocol for real-time communication&amp;quot;. Aims to be like SMTP for real-time communication between different service providers.&lt;br /&gt;
* [http://www.mediachain.io Mediachain] - a &amp;quot;blockchain data solution for connecting applications to media and information about it&amp;quot;. Best-known as an attribution engine for content creators.&lt;br /&gt;
* [https://namecoin.org Namecoin] - an &amp;quot;experimental open-source technology which improves decentralization, security, censorship resistance, privacy, and speed of certain components of the Internet infrastructure such as DNS and identities&amp;quot;.&lt;br /&gt;
* [https://www.openbazaar.org OpenBazaar] - &amp;quot;an open source project developing a protocol for e-commerce transactions in a fully decentralized marketplace&amp;quot;.&lt;br /&gt;
* [https://github.com/blockai-unofficial/openpublish Open Publish] - &amp;quot;a publishing protocol for registering media as a digital asset on the Bitcoin blockchain&amp;quot;.&lt;br /&gt;
* [http://www.osiris-sps.org Osiris] - a &amp;quot;freeware program used to create web portals distributed via peer-to-peer networking (P2P) and autonomous from centralized servers&amp;quot;. Mostly defunct, although the [https://en.wikipedia.org/wiki/Osiris_(software) Wikipedia page] outlines some interesting features around reputation and &#039;anarchist&#039; vs &#039;monarchist&#039; community structures.&lt;br /&gt;
* [https://www.producthunt.com/topics/artificial-intelligence?subtopic=88 Product Hunt | Artificial Intelligence | APIs] - a continually-updated list of products/services using A.I. APIs. Useful for seeing what&#039;s out there to build upon.&lt;br /&gt;
* [https://sia.tech Sia] - an example of co-operative cloud storage, build on blockchain technology. Depends on cryptocurrency called &#039;Siacoin&#039;.&lt;br /&gt;
* [https://storj.io Storj] - another example of co-operative cloud storage. End-to-end encrypted, blockchain-based.&lt;br /&gt;
* [https://skipflag.com SkipFlag] - &amp;quot;a knowledge base that builds itself&amp;quot; using your &amp;quot;existing conversations, support tickets, and other communication... to autonomously answer questions&amp;quot;.&lt;br /&gt;
* [https://socialhome.network Socialhome] - &amp;quot;allows you to build a rich profile that federates across the federated social web&amp;quot;.&lt;br /&gt;
* [https://steemit.com Steem] - a &amp;quot;social news service which runs a blogging and social networking website on top of a blockchain database, known as Steem. The service produces STEEM and Steem Dollars which are tradeable tokens users obtain for posting, discovering, and commenting on interesting content.&amp;quot;&lt;br /&gt;
* [https://github.com/ethersphere/swarm Swarm] - a &amp;quot;distributed storage platform and content distribution service&amp;quot;. Users don&#039;t notice much difference to regular websites, except that &amp;quot;uploads are not to a specific server&amp;quot; meaning that Swarm is &amp;quot;DDOS-resistant, zero-downtime, fault-tolerant and censorship-resistant as well as self-sustaining due to a built-in incentive system&amp;quot;. Free and open source.&lt;br /&gt;
* [http://www.trsst.com trsst] - &amp;quot;looks and feels like twitter but encrypted and anonymized and decentralized and only you hold the keys&amp;quot;.&lt;br /&gt;
* [http://twister.net.co Twister] - a &amp;quot;fully decentralized P2P microblogging platform leveraging from the free software implementations of Bitcoin and BitTorrent protocols&amp;quot;.&lt;br /&gt;
* [https://unhosted.org Unhosted] - &amp;quot;also known as &amp;quot;serverless&amp;quot;, &amp;quot;client-side&amp;quot;, or &amp;quot;static&amp;quot; web apps, unhosted web apps do not send your user data to their server. Either you connect your own server at runtime, or your data stays within the browser.&amp;quot;&lt;br /&gt;
* [https://en.wikipedia.org/wiki/WebRTC WebRTC] - stands for Web Real Time Communication, and is &amp;quot;a collection of communications protocols and application programming interfaces that enable real-time communication over peer-to-peer connections&amp;quot;. Used for &amp;quot;video conferencing, file transfer, chat, or desktop sharing without the need of either internal or external plugins&amp;quot;. Supported in all major desktop and mobile browsers as of iOS 11. Developed by W3C members.&lt;br /&gt;
* [https://zeronet.io ZeroNet] - a &amp;quot;decentralized Internet-like network of peer-to-peer users&amp;quot;. Fully open source. Uses bitcoin cryptography to identify sites (instead of IP addresses) and bittorrent technology to propagate changes within the network. Sites are accessed via a web browser, but served from localhost.&lt;br /&gt;
* [https://en.m.wikipedia.org/wiki/Zooko&#039;s_triangle Zooko&#039;s triangle] - interesting less for the theory, more for the technologies / approaches which refute the conjecture. Notably: [https://blockstack.org Blockstack], [https://gnunet.org GNUnet], and [http://openalias.org OpenAlias]&lt;br /&gt;
&lt;br /&gt;
=== Interesting features ===&lt;br /&gt;
&lt;br /&gt;
=== Controlled taxonomy ===&lt;br /&gt;
&lt;br /&gt;
[[File:vero-taxonomy.jpg|200px|Vero]]&lt;br /&gt;
&lt;br /&gt;
[[File:path-sharing.jpg|200px|Path]]&lt;br /&gt;
&lt;br /&gt;
[https://www.vero.co/ Vero] is a new social network that categorises what you can share, which are then grouped into &#039;collections&#039;. [https://path.com Path] does something similar.&lt;br /&gt;
&lt;br /&gt;
==== Layers of conversation ====&lt;br /&gt;
&lt;br /&gt;
[[File:medium-responses.png|400px|Medium]]&lt;br /&gt;
&lt;br /&gt;
[https://medium.com Medium], the publishing platform / social network, allows you to see who in your network has replied to posts you have written. You can view all responses and conversations by clicking a button to show the &#039;&#039;whole&#039;&#039; network.&lt;br /&gt;
&lt;br /&gt;
==== Collab button ====&lt;br /&gt;
&lt;br /&gt;
[[File:ello-collab.png|400px|Ello]]&lt;br /&gt;
&lt;br /&gt;
[https://ello.co/wtf/support/collab-and-hire Ello], the social network, has a &#039;Collab&#039; button which users can turn on if they are up for collaborations with other users. There&#039;s also a &#039;Hire Me&#039; button for freelancers and consultants, as detailed on [https://ello.co/wtf/support/collab-and-hire/ this page].&lt;br /&gt;
&lt;br /&gt;
==== Decision-making ====&lt;br /&gt;
&lt;br /&gt;
[[File:loomio-voting.png|400px|Loomio]]&lt;br /&gt;
&lt;br /&gt;
[https://www.loomio.org/ Loomio] is a tool that allows for discussion but also for distributed decision-making. It came out of the creators&#039; experiences with the Occupy movement.&lt;br /&gt;
&lt;br /&gt;
==== Threaded conversations ====&lt;br /&gt;
&lt;br /&gt;
[[File:slack-threaded-conversations.gif|400px|Slack]]&lt;br /&gt;
&lt;br /&gt;
[https://slack.com Slack] is a workplace chat tool that allows for channels, but also threaded conversations within those channels. Further details available in [https://slackhq.com/threaded-messaging-comes-to-slack-417ffba054bd this post].&lt;br /&gt;
&lt;br /&gt;
==== Voting up threads ====&lt;br /&gt;
&lt;br /&gt;
[[File:product-hunt.png|400px|Product Hunt]]&lt;br /&gt;
&lt;br /&gt;
[https://www.producthunt.com Product Hunt] allows people to demonstrate new products and services, which can then be &#039;upvoted&#039;. A similar system, but in a support-focused environment, is provided by [https://stackoverflow.com Stack Overflow].&lt;br /&gt;
&lt;br /&gt;
==== Bookmarking ====&lt;br /&gt;
&lt;br /&gt;
[[File:pinboard.png|400px|Pinboard]]&lt;br /&gt;
&lt;br /&gt;
[https://pinboard.in Pinboard] is a tool that allows people to quickly and easily bookmark sites for themselves and others. Tagging is available. [http://pinboard.in/popular Popular links] are aggregated into a feed which is publicly-accessible.&lt;br /&gt;
&lt;br /&gt;
==== Trusted profiles/accounts ====&lt;br /&gt;
&lt;br /&gt;
[[File:keybase.png|400px|Keybase]]&lt;br /&gt;
&lt;br /&gt;
[https://keybase.io Keybase] is a security app for mobile phones and computers. It provides a trusted way to verify identity and ownership of accounts. More recently, they&#039;ve added [https://keybase.io/blog/introducing-keybase-teams Slack-like social networking features] - but end-to-end encrypted. Keybase also has an [https://keybase.io/docs/extension interesting browser extension] that allows you to leave encrypted messages for people, even before they&#039;ve joined the service!&lt;br /&gt;
&lt;br /&gt;
==== Deep-work mode ====&lt;br /&gt;
&lt;br /&gt;
[[File:stride.png|400px|Stride]]&lt;br /&gt;
&lt;br /&gt;
Atlassian&#039;s new team chat app, [https://stride.com Stride] has many of the same features as other team chat apps. However, they have a &#039;deep work&#039; mode which allows users to block out time where they are not disturbed and other people are told what they&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
==== Built-in voice/video chat ====&lt;br /&gt;
&lt;br /&gt;
[[File:microsoft-teams.png|400px|Teams]]&lt;br /&gt;
&lt;br /&gt;
[https://products.office.com/en-us/microsoft-teams/group-chat-software Microsoft Teams], like many team chat apps, has voice and video chat functionality built-in. This allows users to switch seamlessly from text chat to a voice/video discussion.&lt;br /&gt;
&lt;br /&gt;
==== Shared to-do functionality ====&lt;br /&gt;
&lt;br /&gt;
[[File:basecamp.png|400px|Basecamp]]&lt;br /&gt;
&lt;br /&gt;
[https://basecamp.com Basecamp] is a project management application. It has a shared to-do feature, where people can check off something that has been assigned to them - and other people are notified that they have done so.&lt;br /&gt;
&lt;br /&gt;
==== Filtering stream by language ====&lt;br /&gt;
&lt;br /&gt;
[[File:mastodon-languages.png|400px|Mastodon languages]]&lt;br /&gt;
&lt;br /&gt;
[https://joinmastodon.org Mastodon] is an open-source, decentralised, federated microblogging network. One of its features is to be able to filter the stream of &#039;toots&#039; (it&#039;s equivalent of Twitter&#039;s &#039;tweets&#039;) in languages of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Connect with other educators ====&lt;br /&gt;
&lt;br /&gt;
[[File:edmodo.png|400px|Edmodo]]&lt;br /&gt;
&lt;br /&gt;
As part of its onboarding process for new users, [https://www.edmodo.com Edmodo] encourages those who self-identify as teachers to &amp;quot;join discussions and share resources with other educators!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== NGDLE ===&lt;br /&gt;
&lt;br /&gt;
[[File:NGDLE.jpg|400px|NGDLE - Credit: University of Minnesota, Office of Information Technology]]&lt;br /&gt;
&lt;br /&gt;
NGDLE stands for Next Generation Digital Learning Environment. A useful overview of the history of the concept since it was coined in 2015 is provided in [https://er.educause.edu/articles/2017/7/the-ngdle-we-are-the-architects this EDUCAUSE article]. In a post from 2016, [https://clintlalonde.net/2016/02/25/ngdle-and-open-edtech Clint Lalonde] sums up the NGDLE as &amp;quot;the idea that the next generation of learning tools isn’t the single monolithic LMS, but rather a series of applications connected together using different sets of emerging and established learning tool standards&amp;quot;. The original report can be found [https://library.educause.edu/resources/2015/4/the-next-generation-digital-learning-environment-a-report-on-research here] with a [https://library.educause.edu/resources/2015/12/7-things-you-should-know-about-ngdle 7 Things You Should Know About NGDLE] brief also available.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/research/other&amp;diff=58934</id>
		<title>MoodleNet/research/other</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/research/other&amp;diff=58934"/>
		<updated>2021-05-31T12:45:20Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* Inspiration */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[File:search-refine-curate.png|CC BY-ND Bryan Mathers|thumb]]&lt;br /&gt;
&lt;br /&gt;
== Other similar systems ==&lt;br /&gt;
&lt;br /&gt;
This page lists resource-centric social websites and services. There are at least three different types:&lt;br /&gt;
* &#039;&#039;&#039;Bookmarking&#039;&#039;&#039; - This kind of platform cater for people who want to be able to quickly and easily retrieve single resources in their entirety. Primarily focused on the individual, most allow for social sharing, profiles, and discovery. &lt;br /&gt;
* &#039;&#039;&#039;Note-taking&#039;&#039;&#039; - This kind of platform suits people doing research, as they are focused on highlighting, taking notes, or otherwise &#039;clipping&#039; useful information to come back to later. They are either public or private by default, but either way can be shared with other users.&lt;br /&gt;
* &#039;&#039;&#039;Curation&#039;&#039;&#039; - This kind of platform allows users to create collections of resources for various purposes. These can then be shared with other users.&lt;br /&gt;
&lt;br /&gt;
The MoodleNet project is focused on the third of these: &#039;&#039;&#039;curation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Bookmarking ===&lt;br /&gt;
&lt;br /&gt;
* [https://www.basketapp.net Basket]&lt;br /&gt;
* [https://del.icio.us Del.icio.us]&lt;br /&gt;
* [https://www.elcurator.net/en elCurator]&lt;br /&gt;
* [http://pinboard.in Pinboard]&lt;br /&gt;
* [https://getpocket.com Pocket]&lt;br /&gt;
* [https://raindrop.io Raindrop.io] &lt;br /&gt;
* [https://refind.com Refind]&lt;br /&gt;
* [http://saved.io Saved.io]&lt;br /&gt;
* [https://github.com/shaarli/shaarli Shaarli]&lt;br /&gt;
* [http://sitebar.org SiteBar]&lt;br /&gt;
* [https://stumbleupon.com StumbleUpon] &#039;&#039;(note: the [https://en.wikipedia.org/wiki/StumbleUpon Wikipedia page] for StumbleUpon helpfully includes a diagram its information model for user profiles)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Note-taking ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.bibsonomy.org BibSonomy]&lt;br /&gt;
* [https://www.diigo.com Diigo]&lt;br /&gt;
* [https://evernote.com Evernote]&lt;br /&gt;
* [https://web.hypothes.is Hypothes.is]&lt;br /&gt;
* [https://www.lumioapp.com Lumio]&lt;br /&gt;
* [https://www.ravelry.com Ravelry]&lt;br /&gt;
* [https://thinkery.me Thinkery]&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Curation ===&lt;br /&gt;
&lt;br /&gt;
==== Are.na ====&lt;br /&gt;
[[File:arena-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.are.na Are.na] describes itself as &amp;quot;A visual platform that helps you think.&amp;quot; It is pursuing an equity crowdfunding route, based on the message that &#039;social media is broken&#039;. &lt;br /&gt;
* &amp;quot;Social networks depend on addicted users to sell more ads and harvest more data. If we want our attention back, we need a different model.&amp;quot;&lt;br /&gt;
* &amp;quot;No ads, no likes, no distractions.&amp;quot;&lt;br /&gt;
* &amp;quot;Helping you think.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Niice ====&lt;br /&gt;
[[File:niice.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://niice.co Niice] positions itself as a place for teams to gather, share, and discuss ideas. It integrates with Slack.&lt;br /&gt;
* &amp;quot;Speak visually&amp;quot;&lt;br /&gt;
* &amp;quot;Gather, share &amp;amp; discuss ideas with your team&amp;quot;&lt;br /&gt;
* &amp;quot;The Ultimate Canvas for Creative Discussion&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Pearltrees ====&lt;br /&gt;
[[File:pearltrees-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.pearltrees.com Pearltrees] allows users to &amp;quot;save everything&amp;quot; from web pages to notes and photographs in a series of collections. It has a &#039;related connections&#039; button to discover similar collections and people. Collections are visible to everyone unless users pay for the Premium, Education, or Enterprise versions.&lt;br /&gt;
* &amp;quot;Organize everything&amp;quot;&lt;br /&gt;
* &amp;quot;It&#039;s quick and it&#039;s free&amp;quot;&lt;br /&gt;
* &amp;quot;Collaborate, share, and discover your way&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Pinterest ====&lt;br /&gt;
[[File:pinterest-follow.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.pinterest.com Pinterest] is a collections-based platform with social features. They introduced a new dedicated &#039;follow&#039; tab in March 2018 to follow people and collections.&lt;br /&gt;
* &amp;quot;Find and plan your next project&amp;quot;&lt;br /&gt;
* &amp;quot;Explore your interests to find the right ideas for you. As you discover new things to try, you’ll get personalized recommendations picked from the billions of ideas already on Pinterest&amp;quot;&lt;br /&gt;
* &amp;quot;Easily save and organize your ideas in any way you want. You can plan for family dinners, home makeovers, weekend getaways and anything else you want to try&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Scoop.it! ====&lt;br /&gt;
[[File:scoop-it-screenshot.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.scoop.it Scoop.it!] is a content curation tool, primarily aimed at individuals looking to develop their professional profile by becoming a &#039;thought leader&#039; or brands who aim to improve their content marketing.&lt;br /&gt;
* &amp;quot;Research and publish the best content&amp;quot;&lt;br /&gt;
* &amp;quot;Publish your topic page with curated content in minutes. Distribute it automatically with your network to build your professional brand.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Snupps ====&lt;br /&gt;
[[File:snupps-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.snupps.com Snupps] is a place to track the things you own and share photos of them with others who have similar interests. The exhortation is for users to &#039;Collect, Organize &amp;amp; Share!&#039;&lt;br /&gt;
* &amp;quot;Explore collections and get inspired by what’s trending.&amp;quot;&lt;br /&gt;
* &amp;quot;Keep track of what you own. Getting organized has never been so simple.&amp;quot;&lt;br /&gt;
* &amp;quot;Be part of a community. Connect with people who share your passions.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Tagpacker ====&lt;br /&gt;
[[File:tagpacker-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://tagpacker.com Tagpacker] describes itself as a replacement to bookmarking, allowing users to not only tag sites that they visit into collections, but curate those tags into groups. Their business model is &amp;quot;based on advertising and commissions&amp;quot;. &lt;br /&gt;
* &amp;quot;Easily collect, organize, and share links you love&amp;quot;&lt;br /&gt;
* &amp;quot;Collect links you love / Organize things your way / Share your expertise&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Webjets ====&lt;br /&gt;
[[File:webjets-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[http://webjets.io Webjets] is a card-based system for organising information.&lt;br /&gt;
* &amp;quot;The creative desktop for all things that matter&amp;quot;&lt;br /&gt;
* &amp;quot;Organize intuitively&amp;quot;&lt;br /&gt;
* &amp;quot;Collect / Organize / Synchronize / Search / Collaborate / Publish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Wookmark ====&lt;br /&gt;
[[File:wookmark-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[http://www.wookmark.com Wookmark] describes itself as a &#039;visual archive&#039;. Images can be bookmarked and curated into collections which are then shared (and &#039;liked&#039;) by others. A Wookmark account costs $20 per year.&lt;br /&gt;
* &amp;quot;Get your profile, collect your favorite images, and share with others.&amp;quot;&lt;br /&gt;
* &amp;quot;Wookmark is a tool to bookmark images, build mood boards and share visual inspiration.&amp;quot;&lt;br /&gt;
* &amp;quot;Use groups to build mood boards, share privately with others, and keep things tidy.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== To add ====&lt;br /&gt;
&lt;br /&gt;
* [http://vi.sualize.us visualizeus]&lt;br /&gt;
* [https://weheartit.com We Heart It]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/inspiration&amp;diff=58933</id>
		<title>MoodleNet/inspiration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/inspiration&amp;diff=58933"/>
		<updated>2021-05-31T12:45:01Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet/inspiration to MoodleNet/research/other&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[MoodleNet/research/other]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/research/other&amp;diff=58932</id>
		<title>MoodleNet/research/other</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/research/other&amp;diff=58932"/>
		<updated>2021-05-31T12:45:01Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet/inspiration to MoodleNet/research/other&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
[[File:search-refine-curate.png|CC BY-ND Bryan Mathers|thumb]]&lt;br /&gt;
&lt;br /&gt;
== Inspiration ==&lt;br /&gt;
&lt;br /&gt;
This page lists resource-centric social websites and services. There are at least three different types:&lt;br /&gt;
* &#039;&#039;&#039;Bookmarking&#039;&#039;&#039; - This kind of platform cater for people who want to be able to quickly and easily retrieve single resources in their entirety. Primarily focused on the individual, most allow for social sharing, profiles, and discovery. &lt;br /&gt;
* &#039;&#039;&#039;Note-taking&#039;&#039;&#039; - This kind of platform suits people doing research, as they are focused on highlighting, taking notes, or otherwise &#039;clipping&#039; useful information to come back to later. They are either public or private by default, but either way can be shared with other users.&lt;br /&gt;
* &#039;&#039;&#039;Curation&#039;&#039;&#039; - This kind of platform allows users to create collections of resources for various purposes. These can then be shared with other users.&lt;br /&gt;
&lt;br /&gt;
The MoodleNet project is focused on the third of these: &#039;&#039;&#039;curation&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Bookmarking ===&lt;br /&gt;
&lt;br /&gt;
* [https://www.basketapp.net Basket]&lt;br /&gt;
* [https://del.icio.us Del.icio.us]&lt;br /&gt;
* [https://www.elcurator.net/en elCurator]&lt;br /&gt;
* [http://pinboard.in Pinboard]&lt;br /&gt;
* [https://getpocket.com Pocket]&lt;br /&gt;
* [https://raindrop.io Raindrop.io] &lt;br /&gt;
* [https://refind.com Refind]&lt;br /&gt;
* [http://saved.io Saved.io]&lt;br /&gt;
* [https://github.com/shaarli/shaarli Shaarli]&lt;br /&gt;
* [http://sitebar.org SiteBar]&lt;br /&gt;
* [https://stumbleupon.com StumbleUpon] &#039;&#039;(note: the [https://en.wikipedia.org/wiki/StumbleUpon Wikipedia page] for StumbleUpon helpfully includes a diagram its information model for user profiles)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Note-taking ===&lt;br /&gt;
&lt;br /&gt;
* [http://www.bibsonomy.org BibSonomy]&lt;br /&gt;
* [https://www.diigo.com Diigo]&lt;br /&gt;
* [https://evernote.com Evernote]&lt;br /&gt;
* [https://web.hypothes.is Hypothes.is]&lt;br /&gt;
* [https://www.lumioapp.com Lumio]&lt;br /&gt;
* [https://www.ravelry.com Ravelry]&lt;br /&gt;
* [https://thinkery.me Thinkery]&lt;br /&gt;
&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
=== Curation ===&lt;br /&gt;
&lt;br /&gt;
==== Are.na ====&lt;br /&gt;
[[File:arena-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.are.na Are.na] describes itself as &amp;quot;A visual platform that helps you think.&amp;quot; It is pursuing an equity crowdfunding route, based on the message that &#039;social media is broken&#039;. &lt;br /&gt;
* &amp;quot;Social networks depend on addicted users to sell more ads and harvest more data. If we want our attention back, we need a different model.&amp;quot;&lt;br /&gt;
* &amp;quot;No ads, no likes, no distractions.&amp;quot;&lt;br /&gt;
* &amp;quot;Helping you think.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Niice ====&lt;br /&gt;
[[File:niice.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://niice.co Niice] positions itself as a place for teams to gather, share, and discuss ideas. It integrates with Slack.&lt;br /&gt;
* &amp;quot;Speak visually&amp;quot;&lt;br /&gt;
* &amp;quot;Gather, share &amp;amp; discuss ideas with your team&amp;quot;&lt;br /&gt;
* &amp;quot;The Ultimate Canvas for Creative Discussion&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Pearltrees ====&lt;br /&gt;
[[File:pearltrees-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.pearltrees.com Pearltrees] allows users to &amp;quot;save everything&amp;quot; from web pages to notes and photographs in a series of collections. It has a &#039;related connections&#039; button to discover similar collections and people. Collections are visible to everyone unless users pay for the Premium, Education, or Enterprise versions.&lt;br /&gt;
* &amp;quot;Organize everything&amp;quot;&lt;br /&gt;
* &amp;quot;It&#039;s quick and it&#039;s free&amp;quot;&lt;br /&gt;
* &amp;quot;Collaborate, share, and discover your way&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Pinterest ====&lt;br /&gt;
[[File:pinterest-follow.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.pinterest.com Pinterest] is a collections-based platform with social features. They introduced a new dedicated &#039;follow&#039; tab in March 2018 to follow people and collections.&lt;br /&gt;
* &amp;quot;Find and plan your next project&amp;quot;&lt;br /&gt;
* &amp;quot;Explore your interests to find the right ideas for you. As you discover new things to try, you’ll get personalized recommendations picked from the billions of ideas already on Pinterest&amp;quot;&lt;br /&gt;
* &amp;quot;Easily save and organize your ideas in any way you want. You can plan for family dinners, home makeovers, weekend getaways and anything else you want to try&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Scoop.it! ====&lt;br /&gt;
[[File:scoop-it-screenshot.jpg|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.scoop.it Scoop.it!] is a content curation tool, primarily aimed at individuals looking to develop their professional profile by becoming a &#039;thought leader&#039; or brands who aim to improve their content marketing.&lt;br /&gt;
* &amp;quot;Research and publish the best content&amp;quot;&lt;br /&gt;
* &amp;quot;Publish your topic page with curated content in minutes. Distribute it automatically with your network to build your professional brand.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Snupps ====&lt;br /&gt;
[[File:snupps-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://www.snupps.com Snupps] is a place to track the things you own and share photos of them with others who have similar interests. The exhortation is for users to &#039;Collect, Organize &amp;amp; Share!&#039;&lt;br /&gt;
* &amp;quot;Explore collections and get inspired by what’s trending.&amp;quot;&lt;br /&gt;
* &amp;quot;Keep track of what you own. Getting organized has never been so simple.&amp;quot;&lt;br /&gt;
* &amp;quot;Be part of a community. Connect with people who share your passions.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Tagpacker ====&lt;br /&gt;
[[File:tagpacker-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[https://tagpacker.com Tagpacker] describes itself as a replacement to bookmarking, allowing users to not only tag sites that they visit into collections, but curate those tags into groups. Their business model is &amp;quot;based on advertising and commissions&amp;quot;. &lt;br /&gt;
* &amp;quot;Easily collect, organize, and share links you love&amp;quot;&lt;br /&gt;
* &amp;quot;Collect links you love / Organize things your way / Share your expertise&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Webjets ====&lt;br /&gt;
[[File:webjets-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[http://webjets.io Webjets] is a card-based system for organising information.&lt;br /&gt;
* &amp;quot;The creative desktop for all things that matter&amp;quot;&lt;br /&gt;
* &amp;quot;Organize intuitively&amp;quot;&lt;br /&gt;
* &amp;quot;Collect / Organize / Synchronize / Search / Collaborate / Publish&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== Wookmark ====&lt;br /&gt;
[[File:wookmark-screenshot.png|400px]]&lt;br /&gt;
&lt;br /&gt;
[http://www.wookmark.com Wookmark] describes itself as a &#039;visual archive&#039;. Images can be bookmarked and curated into collections which are then shared (and &#039;liked&#039;) by others. A Wookmark account costs $20 per year.&lt;br /&gt;
* &amp;quot;Get your profile, collect your favorite images, and share with others.&amp;quot;&lt;br /&gt;
* &amp;quot;Wookmark is a tool to bookmark images, build mood boards and share visual inspiration.&amp;quot;&lt;br /&gt;
* &amp;quot;Use groups to build mood boards, share privately with others, and keep things tidy.&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==== To add ====&lt;br /&gt;
&lt;br /&gt;
* [http://vi.sualize.us visualizeus]&lt;br /&gt;
* [https://weheartit.com We Heart It]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58931</id>
		<title>MoodleNet</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58931"/>
		<updated>2021-05-31T11:06:26Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* Archive */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Moodlenet-logo.png|400px]]&lt;br /&gt;
&lt;br /&gt;
== What is MoodleNet? ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is our new social network to share and curate open educational resources with educators world-wide.  It is integrated closely with Moodle LMS and Moodle Workplace to make resources easy to find and use, but can be useful even if you don&#039;t use Moodle LMS. MoodleNet is also intended as a way to build your profile as an educator.&lt;br /&gt;
&lt;br /&gt;
Importantly, MoodleNet is designed to be a federated, flexible Open Education Technology that is not controlled by a single entity, or subject to a single point of failure.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Current status ==&lt;br /&gt;
&#039;&#039;Last updated: 31 May 2021&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet 1.x was abandoned by the team in 2021 because it was heading down the wrong path.  The project was recently rebooted (January 2021) with a new team, new architecture and a simpler new design.&lt;br /&gt;
&lt;br /&gt;
== Roadmap ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;15 August 2021&#039;&#039;&#039; - MVP for wider community testing and feedback&lt;br /&gt;
* &#039;&#039;&#039;31 August 2021&#039;&#039;&#039; - Beta release , feature complete for 2.0 release.&lt;br /&gt;
* &#039;&#039;&#039;15 September 2021&#039;&#039;&#039; - 2.0 release!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Important links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitlab.com/moodlenet Code repository]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=8726 MoodleNet news and discussion]&lt;br /&gt;
&lt;br /&gt;
== Archive ==&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/inspiration Inspiration]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/research Other research]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Copyright_Directive European Copyright Directive]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/DPIA Data Protection Impact Assessment]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:MoodleNet]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet-research&amp;diff=58930</id>
		<title>MoodleNet-research</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet-research&amp;diff=58930"/>
		<updated>2021-05-31T11:06:09Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet-research to MoodleNet/research&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[MoodleNet/research]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/research&amp;diff=58929</id>
		<title>MoodleNet/research</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/research&amp;diff=58929"/>
		<updated>2021-05-31T11:06:08Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet-research to MoodleNet/research&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== DMCA ===&lt;br /&gt;
&lt;br /&gt;
From [https://en.wikipedia.org/wiki/Digital_Millennium_Copyright_Act Wikipedia]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;The Digital Millennium Copyright Act (DMCA) is a 1998 United States copyright law that implements two 1996 treaties of the World Intellectual Property Organization (WIPO). It criminalizes production and dissemination of technology, devices, or services intended to circumvent measures that control access to copyrighted works (commonly known as digital rights management or DRM). It also criminalizes the act of circumventing an access control, whether or not there is actual infringement of copyright itself. In addition, the DMCA heightens the penalties for copyright infringement on the Internet.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...and:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;DMCA Title II, the Online Copyright Infringement Liability Limitation Act (&amp;quot;OCILLA&amp;quot;), creates a safe harbor for online service providers (OSPs, including ISPs) against copyright infringement liability, provided they meet specific requirements. OSPs must adhere to and qualify for certain prescribed safe harbor guidelines and promptly block access to alleged infringing material (or remove such material from their systems) when they receive notification of an infringement claim from a copyright holder or the copyright holder&#039;s agent. OCILLA also includes a counternotification provision that offers OSPs a safe harbor from liability to their users when users claim that the material in question is not, in fact, infringing. OCILLA also facilitates issuing of subpoenas against OSPs to provide their users&#039; identity.&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Social networks integrating &#039;currency&#039; ===&lt;br /&gt;
&lt;br /&gt;
* [https://memo.cash/ Memo]&lt;br /&gt;
* [https://www.minds.com/ Minds]&lt;br /&gt;
* [https://steemit.com/ Steemit]&lt;br /&gt;
* [https://tri.cash/ Trillion]&lt;br /&gt;
* [http://www.yy.com/ YY.com] &#039;&#039;(Chinese)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== DPIA ===&lt;br /&gt;
&lt;br /&gt;
A [https://ico.org.uk/for-organisations/guide-to-the-general-data-protection-regulation-gdpr/data-protection-impact-assessments-dpias/what-is-a-dpia/ Data Protection Impact Assessment] &amp;quot;is a process designed to help you systematically analyse, identify and minimise the data protection risks of a project or plan&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
We need to decide whether MoodleNet meets any of the three criteria which would necessitate a DPIA:&lt;br /&gt;
&lt;br /&gt;
# Systematic and extensive profiling with significant effects&lt;br /&gt;
# Large scale use of sensitive data&lt;br /&gt;
# Public monitoring&lt;br /&gt;
&lt;br /&gt;
It may be a good idea to create a DPIA in any case, as part of our GDPR compliance.&lt;br /&gt;
&lt;br /&gt;
=== Translation platforms ===&lt;br /&gt;
&lt;br /&gt;
* [https://www.applanga.com/ Applanga]&lt;br /&gt;
* [https://crowdin.com Crowdin]&lt;br /&gt;
* [https://www.memoq.com/en/memoq-translator-free memoq]&lt;br /&gt;
* [https://poeditor.com/ POEditor]&lt;br /&gt;
* [http://pootle.translatehouse.org/index.html Pootle]&lt;br /&gt;
* [https://www.textunited.com/ TextUnited]&lt;br /&gt;
* [https://www.transifex.com/ Transifex]&lt;br /&gt;
* [http://zanata.org/ Zanata]&lt;br /&gt;
&lt;br /&gt;
=== Accessibility ===&lt;br /&gt;
&lt;br /&gt;
* [https://accessibility.blog.gov.uk/ Gov.uk accessibility]&lt;br /&gt;
* [https://www.marcozehe.de/2015/12/14/the-web-accessibility-basics/ Marco&#039;s accessibility blog]&lt;br /&gt;
* [https://www.usability.gov/what-and-why/accessibility.html Usability.gov]&lt;br /&gt;
* [https://www.w3.org/wiki/Accessibility_basics W3C Accessibility basics]&lt;br /&gt;
* [https://www.w3.org/WAI/standards-guidelines/wcag/glance/ Web Content Accessibility Guidelines (WCAG) 2.1]&lt;br /&gt;
* [https://wordpress.org/about/accessibility/ WordPress accessibility]&lt;br /&gt;
&lt;br /&gt;
=== Policy docs from other federated systems ===&lt;br /&gt;
&lt;br /&gt;
[https://the-federation.info/ Federated systems] tend to have a website explaining the service, then link to specific instances. As the terms of service, privacy policy, etc. may differ greatly from instance to instance, the list below takes a popular example of the service.&lt;br /&gt;
&lt;br /&gt;
* [https://diasporafoundation.org/ Diaspora]&lt;br /&gt;
** [https://diasp.org Diasp.org] &lt;br /&gt;
*** [https://diasp.org/terms Terms of service and privacy policy]&lt;br /&gt;
* [https://friendi.ca/ Friendica]&lt;br /&gt;
** [https://libranet.de/ Libranet.de]&lt;br /&gt;
*** [https://libranet.de/friendica Terms of use, data protection and data security] (in German)&lt;br /&gt;
* [https://gnu.io/social/ GNU social]&lt;br /&gt;
** [https://status.pirati.ca Piratica]&lt;br /&gt;
*** [https://status.pirati.ca/doc/privacy Privacy policy]&lt;br /&gt;
* [https://project.hubzilla.org/ Hubzilla]&lt;br /&gt;
** [https://start.hubzilla.org Start.hubzilla.org]&lt;br /&gt;
*** [https://start.hubzilla.org/help/en-gb/TermsOfService Terms of service]&lt;br /&gt;
* [https://joinmastodon.org/ Mastodon]&lt;br /&gt;
** [https://mastodon.social/about Mastodon.social]&lt;br /&gt;
*** [https://mastodon.social/about/more Code of conduct]&lt;br /&gt;
*** [https://mastodon.social/terms Privacy policy]&lt;br /&gt;
* [https://joinmisskey.github.io/en/ Misskey]&lt;br /&gt;
** [https://tri.cash/ Trillion]&lt;br /&gt;
*** [https://tri.cash/news/wp/terms/ Terms of service] &#039;&#039;(note: also uses e-currency)&#039;&#039;&lt;br /&gt;
* [https://zotlabs.com/osada/ Osada]&lt;br /&gt;
** [https://osada.gibberfish.org Osada.gibberfish.org]&lt;br /&gt;
*** [https://osada.gibberfish.org/help/en-gb/TermsOfService Terms of service] &#039;&#039;(essentially the same as Hubzilla)&#039;&#039;&lt;br /&gt;
* [https://joinpeertube.org/en/ PeerTube]&lt;br /&gt;
** [https://pe.ertu.be/ Pe.ertu.be]&lt;br /&gt;
*** [https://pe.ertu.be/about/instance About and terms]&lt;br /&gt;
* [https://pixelfed.org/ PixelFed]&lt;br /&gt;
** [https://pixelfed.social/ Pixelfed.social]&lt;br /&gt;
*** [https://pixelfed.social/site/terms Terms of use]&lt;br /&gt;
*** [https://pixelfed.social/site/privacy Privacy policy]&lt;br /&gt;
* [https://pleroma.social Pleroma]&lt;br /&gt;
** [https://pleroma.site Pleroma.site]&lt;br /&gt;
*** [https://info.pleroma.site/tos.html Terms of service]&lt;br /&gt;
*** [https://info.pleroma.site/ Site info] (include warrant canary, hardware specs, etc.)&lt;br /&gt;
*** [https://info.pleroma.site/federation.html Federation policy]&lt;br /&gt;
*** [https://info.pleroma.site/privacy.html Privacy policy]&lt;br /&gt;
* [https://plume-org.github.io/Plume/ Plume]&lt;br /&gt;
** [https://fediverse.blog Fediverse.blog]&lt;br /&gt;
*** [https://fediverse.blog/about About]&lt;br /&gt;
&lt;br /&gt;
=== Authentication systems ===&lt;br /&gt;
&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Mozilla_Persona Mozilla Persona] (decommissioned, but useful info in project - including [https://web.archive.org/web/20140713180852/http://lloyd.io/how-browserid-works this post])&lt;br /&gt;
* [https://en.wikipedia.org/wiki/OAuth OAuth]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/OpenID OpenID]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Security_Assertion_Markup_Language SAML]&lt;br /&gt;
* [https://en.wikipedia.org/wiki/WebID WebID]&lt;br /&gt;
&lt;br /&gt;
=== Interesting projects, products, and standards ===&lt;br /&gt;
&lt;br /&gt;
* [https://activitypub.rocks/ ActivityPub] - a &amp;quot;decentralized social networking protocol based upon the ActivityStreams 2.0 data format. It provides a client to server API for creating, updating and deleting content, as well as a federated server to server API for delivering notifications and content&amp;quot;. Useful comments and caveats in [https://news.ycombinator.com/item?id=14417315 this Hacker News thread]. The [https://www.w3.org/TR/activitypub/ spec] (latest version: Nov 2017) is well-written.&lt;br /&gt;
* [https://beakerbrowser.com Beaker] - a peer-to-peer browser with tools to create and host websites.&lt;br /&gt;
* [https://www.bigchaindb.com BigchainDB] - a decentralised open-source database with blockchain data structure to enhance scalability, write and read speed, and data extraction capability.&lt;br /&gt;
* [https://blockstack.org Blockstack] - a new network for decentralised applications, including an alternate DNS and public-key infrastructure.&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Cooperative_storage_cloud Co-operative Storage Cloud] - a &amp;quot;decentralized model of networked online storage where data is stored on multiple computers (nodes), hosted by the participants cooperating in the cloud&amp;quot;. &lt;br /&gt;
* [https://cryptosphere.io Cryptosphere] - an &amp;quot;open-source P2P web application platform for decentralized, privacy-preserving software which keeps users in control of their own content&amp;quot;. Defunct?&lt;br /&gt;
* [https://datproject.org Dat] - a &amp;quot;data distribution tool with a version control feature for tracking changes and publishing datasets&amp;quot;. Funded by major donors such as the Knight Foundation and Alfred P. Sloan Foundation.&lt;br /&gt;
* [https://diasporafoundation.org Diaspora] - a &amp;quot;nonprofit, user-owned, distributed social network&amp;quot; consisting of &amp;quot;independently owned nodes (called pods) which interoperate to form the network&amp;quot;.&lt;br /&gt;
* [https://edmodo.com Edmodo] - the app &amp;quot;is probably the closest thing to MoodleNet that exists&amp;quot; according to Martin Dougiamas.&lt;br /&gt;
* [https://ethereum.org Ethereum] - a &amp;quot;decentralized platform that runs smart contracts: applications that run exactly as programmed without any possibility of downtime, censorship, fraud or third party interference&amp;quot;.&lt;br /&gt;
* [https://filecoin.io Filecoin] - an &amp;quot;open-source, public, cryptocurrency and digital payment system intended to be a blockchain-based digital storage and data retrieval method&amp;quot; building on top of IPFS.&lt;br /&gt;
* [https://freenetproject.org Freenet] - a somewhat notorious peer-to-peer platform using the &#039;dark web&#039; for censorship-resistant communication. &#039;Freesites&#039; contains only static content, meaning it cannot provide content that requires a database or server-side scripts.&lt;br /&gt;
* [http://friendi.ca Friendica] - &amp;quot;open source software for a distributed social network&amp;quot; focusing on &amp;quot;effective privacy settings and easy installation of personal servers&amp;quot;. Also allows other social networks and blogs to be integrated.&lt;br /&gt;
* [https://gnunet.org GNUnet] - an &amp;quot;alternative ne twork stack for building secure, decentralized and privacy-preserving distributed applications&amp;quot;. The framework features &amp;quot;link encryption, peer discovery, resource allocation, communication over many transports (such as TCP, UDP, HTTP, HTTPS, WLAN and Bluetooth) and various basic peer-to-peer algorithms for routing, multicast and network size estimation&amp;quot;.&lt;br /&gt;
* [https://gnu.io/social GNU social] - &amp;quot;social communication software for both public and private communications&amp;quot; -  &amp;quot;widely supported and has a large userbase&amp;quot;.&lt;br /&gt;
* [https://project.hubzilla.org Hubzilla] - a &amp;quot;powerful platform for creating interconnected websites featuring a decentralized identity, communications, and permissions framework built using common webserver technology&amp;quot;.&lt;br /&gt;
* [https://geti2p.net/en I2P] - a network that provides &amp;quot;strong privacy protections for communication over the Internet&amp;quot;. Used for serverless email, anonymous websites, gateways to/from the public internet, blogging, forums, realtime chat, filesharing, decentralised file storage, and more.&lt;br /&gt;
* [https://ipdb.io IPDB] - stands for &#039;InterPlanetary DataBase&#039;, a &amp;quot;blockchain database network for the decentralized stack&amp;quot;. It&#039;s ready to use, with strong governance (including many large non-profits).&lt;br /&gt;
* [https://ipfs.io IPFS] - stands for &#039;InterPlanetary File System&#039;, a protocol &amp;quot;designed to create a permanent and decentralized method of storing and sharing files&amp;quot;. Content-addressable, peer-to-peer, distributed file system. Provides a resilient way to serve files, removing duplication and centralisation.&lt;br /&gt;
* [https://github.com/oduwsdl/ipwb IPWB] - stands for &#039;InterPlanetary WayBack&#039; and &amp;quot;facilitates permanence and collaboration in web archives&amp;quot;.&lt;br /&gt;
* [https://www.gitbook.com/book/jedisct1/libsodium/details Libsodium] - the Sodium crypto library is &amp;quot;a modern, easy-to-use software library for encryption, decryption, signatures, password hashing and more&amp;quot;.&lt;br /&gt;
* [http://www.imsglobal.org/activity/learning-tools-interoperability LTI] - stands for Learning Tools Interoperability, a standard developed by IMS Global Learning Consortium. Main use case is to enable web apps, tools or content to connect seamlessly and securely with digital learning environments.&lt;br /&gt;
* [http://www.imsglobal.org/activity/learning-tools-interoperability LTI Advantage] - a new package of extensions to the Learning Tools Interoperability standard that currently includes: Assignment and Grade Services, Deep Linking, and Names and Role Provisioning Service. Allows for better two-way sharing of data between digital learning environments and other apps/services.&lt;br /&gt;
* [https://maidsafe.net Maidsafe] - bills itself as &amp;quot;the world&#039;s first autonomous data network&amp;quot;. Reliant on cryptocurrency, but not blockchain, for network services.&lt;br /&gt;
* [https://joinmastodon.org Mastodon] - a federated social network similar to Twitter, &amp;quot;but administrated as a decentralized federation of independently operated servers running open source software&amp;quot;. Users join a specific instance, and their updates can then be federated to other instances. Mastodon is built on OStatus, meaning that federated Mastodon instances form just one part of a wider &#039;Fediverse&#039;.&lt;br /&gt;
* [https://matrix.org Matrix] - an &amp;quot;open protocol for real-time communication&amp;quot;. Aims to be like SMTP for real-time communication between different service providers.&lt;br /&gt;
* [http://www.mediachain.io Mediachain] - a &amp;quot;blockchain data solution for connecting applications to media and information about it&amp;quot;. Best-known as an attribution engine for content creators.&lt;br /&gt;
* [https://namecoin.org Namecoin] - an &amp;quot;experimental open-source technology which improves decentralization, security, censorship resistance, privacy, and speed of certain components of the Internet infrastructure such as DNS and identities&amp;quot;.&lt;br /&gt;
* [https://www.openbazaar.org OpenBazaar] - &amp;quot;an open source project developing a protocol for e-commerce transactions in a fully decentralized marketplace&amp;quot;.&lt;br /&gt;
* [https://github.com/blockai-unofficial/openpublish Open Publish] - &amp;quot;a publishing protocol for registering media as a digital asset on the Bitcoin blockchain&amp;quot;.&lt;br /&gt;
* [http://www.osiris-sps.org Osiris] - a &amp;quot;freeware program used to create web portals distributed via peer-to-peer networking (P2P) and autonomous from centralized servers&amp;quot;. Mostly defunct, although the [https://en.wikipedia.org/wiki/Osiris_(software) Wikipedia page] outlines some interesting features around reputation and &#039;anarchist&#039; vs &#039;monarchist&#039; community structures.&lt;br /&gt;
* [https://www.producthunt.com/topics/artificial-intelligence?subtopic=88 Product Hunt | Artificial Intelligence | APIs] - a continually-updated list of products/services using A.I. APIs. Useful for seeing what&#039;s out there to build upon.&lt;br /&gt;
* [https://sia.tech Sia] - an example of co-operative cloud storage, build on blockchain technology. Depends on cryptocurrency called &#039;Siacoin&#039;.&lt;br /&gt;
* [https://storj.io Storj] - another example of co-operative cloud storage. End-to-end encrypted, blockchain-based.&lt;br /&gt;
* [https://skipflag.com SkipFlag] - &amp;quot;a knowledge base that builds itself&amp;quot; using your &amp;quot;existing conversations, support tickets, and other communication... to autonomously answer questions&amp;quot;.&lt;br /&gt;
* [https://socialhome.network Socialhome] - &amp;quot;allows you to build a rich profile that federates across the federated social web&amp;quot;.&lt;br /&gt;
* [https://steemit.com Steem] - a &amp;quot;social news service which runs a blogging and social networking website on top of a blockchain database, known as Steem. The service produces STEEM and Steem Dollars which are tradeable tokens users obtain for posting, discovering, and commenting on interesting content.&amp;quot;&lt;br /&gt;
* [https://github.com/ethersphere/swarm Swarm] - a &amp;quot;distributed storage platform and content distribution service&amp;quot;. Users don&#039;t notice much difference to regular websites, except that &amp;quot;uploads are not to a specific server&amp;quot; meaning that Swarm is &amp;quot;DDOS-resistant, zero-downtime, fault-tolerant and censorship-resistant as well as self-sustaining due to a built-in incentive system&amp;quot;. Free and open source.&lt;br /&gt;
* [http://www.trsst.com trsst] - &amp;quot;looks and feels like twitter but encrypted and anonymized and decentralized and only you hold the keys&amp;quot;.&lt;br /&gt;
* [http://twister.net.co Twister] - a &amp;quot;fully decentralized P2P microblogging platform leveraging from the free software implementations of Bitcoin and BitTorrent protocols&amp;quot;.&lt;br /&gt;
* [https://unhosted.org Unhosted] - &amp;quot;also known as &amp;quot;serverless&amp;quot;, &amp;quot;client-side&amp;quot;, or &amp;quot;static&amp;quot; web apps, unhosted web apps do not send your user data to their server. Either you connect your own server at runtime, or your data stays within the browser.&amp;quot;&lt;br /&gt;
* [https://en.wikipedia.org/wiki/WebRTC WebRTC] - stands for Web Real Time Communication, and is &amp;quot;a collection of communications protocols and application programming interfaces that enable real-time communication over peer-to-peer connections&amp;quot;. Used for &amp;quot;video conferencing, file transfer, chat, or desktop sharing without the need of either internal or external plugins&amp;quot;. Supported in all major desktop and mobile browsers as of iOS 11. Developed by W3C members.&lt;br /&gt;
* [https://zeronet.io ZeroNet] - a &amp;quot;decentralized Internet-like network of peer-to-peer users&amp;quot;. Fully open source. Uses bitcoin cryptography to identify sites (instead of IP addresses) and bittorrent technology to propagate changes within the network. Sites are accessed via a web browser, but served from localhost.&lt;br /&gt;
* [https://en.m.wikipedia.org/wiki/Zooko&#039;s_triangle Zooko&#039;s triangle] - interesting less for the theory, more for the technologies / approaches which refute the conjecture. Notably: [https://blockstack.org Blockstack], [https://gnunet.org GNUnet], and [http://openalias.org OpenAlias]&lt;br /&gt;
&lt;br /&gt;
=== Interesting features ===&lt;br /&gt;
&lt;br /&gt;
=== Controlled taxonomy ===&lt;br /&gt;
&lt;br /&gt;
[[File:vero-taxonomy.jpg|200px|Vero]]&lt;br /&gt;
&lt;br /&gt;
[[File:path-sharing.jpg|200px|Path]]&lt;br /&gt;
&lt;br /&gt;
[https://www.vero.co/ Vero] is a new social network that categorises what you can share, which are then grouped into &#039;collections&#039;. [https://path.com Path] does something similar.&lt;br /&gt;
&lt;br /&gt;
==== Layers of conversation ====&lt;br /&gt;
&lt;br /&gt;
[[File:medium-responses.png|400px|Medium]]&lt;br /&gt;
&lt;br /&gt;
[https://medium.com Medium], the publishing platform / social network, allows you to see who in your network has replied to posts you have written. You can view all responses and conversations by clicking a button to show the &#039;&#039;whole&#039;&#039; network.&lt;br /&gt;
&lt;br /&gt;
==== Collab button ====&lt;br /&gt;
&lt;br /&gt;
[[File:ello-collab.png|400px|Ello]]&lt;br /&gt;
&lt;br /&gt;
[https://ello.co/wtf/support/collab-and-hire Ello], the social network, has a &#039;Collab&#039; button which users can turn on if they are up for collaborations with other users. There&#039;s also a &#039;Hire Me&#039; button for freelancers and consultants, as detailed on [https://ello.co/wtf/support/collab-and-hire/ this page].&lt;br /&gt;
&lt;br /&gt;
==== Decision-making ====&lt;br /&gt;
&lt;br /&gt;
[[File:loomio-voting.png|400px|Loomio]]&lt;br /&gt;
&lt;br /&gt;
[https://www.loomio.org/ Loomio] is a tool that allows for discussion but also for distributed decision-making. It came out of the creators&#039; experiences with the Occupy movement.&lt;br /&gt;
&lt;br /&gt;
==== Threaded conversations ====&lt;br /&gt;
&lt;br /&gt;
[[File:slack-threaded-conversations.gif|400px|Slack]]&lt;br /&gt;
&lt;br /&gt;
[https://slack.com Slack] is a workplace chat tool that allows for channels, but also threaded conversations within those channels. Further details available in [https://slackhq.com/threaded-messaging-comes-to-slack-417ffba054bd this post].&lt;br /&gt;
&lt;br /&gt;
==== Voting up threads ====&lt;br /&gt;
&lt;br /&gt;
[[File:product-hunt.png|400px|Product Hunt]]&lt;br /&gt;
&lt;br /&gt;
[https://www.producthunt.com Product Hunt] allows people to demonstrate new products and services, which can then be &#039;upvoted&#039;. A similar system, but in a support-focused environment, is provided by [https://stackoverflow.com Stack Overflow].&lt;br /&gt;
&lt;br /&gt;
==== Bookmarking ====&lt;br /&gt;
&lt;br /&gt;
[[File:pinboard.png|400px|Pinboard]]&lt;br /&gt;
&lt;br /&gt;
[https://pinboard.in Pinboard] is a tool that allows people to quickly and easily bookmark sites for themselves and others. Tagging is available. [http://pinboard.in/popular Popular links] are aggregated into a feed which is publicly-accessible.&lt;br /&gt;
&lt;br /&gt;
==== Trusted profiles/accounts ====&lt;br /&gt;
&lt;br /&gt;
[[File:keybase.png|400px|Keybase]]&lt;br /&gt;
&lt;br /&gt;
[https://keybase.io Keybase] is a security app for mobile phones and computers. It provides a trusted way to verify identity and ownership of accounts. More recently, they&#039;ve added [https://keybase.io/blog/introducing-keybase-teams Slack-like social networking features] - but end-to-end encrypted. Keybase also has an [https://keybase.io/docs/extension interesting browser extension] that allows you to leave encrypted messages for people, even before they&#039;ve joined the service!&lt;br /&gt;
&lt;br /&gt;
==== Deep-work mode ====&lt;br /&gt;
&lt;br /&gt;
[[File:stride.png|400px|Stride]]&lt;br /&gt;
&lt;br /&gt;
Atlassian&#039;s new team chat app, [https://stride.com Stride] has many of the same features as other team chat apps. However, they have a &#039;deep work&#039; mode which allows users to block out time where they are not disturbed and other people are told what they&#039;re working on.&lt;br /&gt;
&lt;br /&gt;
==== Built-in voice/video chat ====&lt;br /&gt;
&lt;br /&gt;
[[File:microsoft-teams.png|400px|Teams]]&lt;br /&gt;
&lt;br /&gt;
[https://products.office.com/en-us/microsoft-teams/group-chat-software Microsoft Teams], like many team chat apps, has voice and video chat functionality built-in. This allows users to switch seamlessly from text chat to a voice/video discussion.&lt;br /&gt;
&lt;br /&gt;
==== Shared to-do functionality ====&lt;br /&gt;
&lt;br /&gt;
[[File:basecamp.png|400px|Basecamp]]&lt;br /&gt;
&lt;br /&gt;
[https://basecamp.com Basecamp] is a project management application. It has a shared to-do feature, where people can check off something that has been assigned to them - and other people are notified that they have done so.&lt;br /&gt;
&lt;br /&gt;
==== Filtering stream by language ====&lt;br /&gt;
&lt;br /&gt;
[[File:mastodon-languages.png|400px|Mastodon languages]]&lt;br /&gt;
&lt;br /&gt;
[https://joinmastodon.org Mastodon] is an open-source, decentralised, federated microblogging network. One of its features is to be able to filter the stream of &#039;toots&#039; (it&#039;s equivalent of Twitter&#039;s &#039;tweets&#039;) in languages of your choice.&lt;br /&gt;
&lt;br /&gt;
==== Connect with other educators ====&lt;br /&gt;
&lt;br /&gt;
[[File:edmodo.png|400px|Edmodo]]&lt;br /&gt;
&lt;br /&gt;
As part of its onboarding process for new users, [https://www.edmodo.com Edmodo] encourages those who self-identify as teachers to &amp;quot;join discussions and share resources with other educators!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== NGDLE ===&lt;br /&gt;
&lt;br /&gt;
[[File:NGDLE.jpg|400px|NGDLE - Credit: University of Minnesota, Office of Information Technology]]&lt;br /&gt;
&lt;br /&gt;
NGDLE stands for Next Generation Digital Learning Environment. A useful overview of the history of the concept since it was coined in 2015 is provided in [https://er.educause.edu/articles/2017/7/the-ngdle-we-are-the-architects this EDUCAUSE article]. In a post from 2016, [https://clintlalonde.net/2016/02/25/ngdle-and-open-edtech Clint Lalonde] sums up the NGDLE as &amp;quot;the idea that the next generation of learning tools isn’t the single monolithic LMS, but rather a series of applications connected together using different sets of emerging and established learning tool standards&amp;quot;. The original report can be found [https://library.educause.edu/resources/2015/4/the-next-generation-digital-learning-environment-a-report-on-research here] with a [https://library.educause.edu/resources/2015/12/7-things-you-should-know-about-ngdle 7 Things You Should Know About NGDLE] brief also available.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet-consultancy&amp;diff=58928</id>
		<title>MoodleNet-consultancy</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet-consultancy&amp;diff=58928"/>
		<updated>2021-05-31T11:04:04Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet-consultancy to 1.0/MoodleNet-consultancy&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[1.0/MoodleNet-consultancy]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Decision_Log&amp;diff=58926</id>
		<title>MoodleNet/Decision Log</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Decision_Log&amp;diff=58926"/>
		<updated>2021-05-31T11:03:17Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet/Decision Log to MoodleNet/1.0/Decision Log&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[MoodleNet/1.0/Decision Log]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/1.0/Decision_Log&amp;diff=58925</id>
		<title>MoodleNet/1.0/Decision Log</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/1.0/Decision_Log&amp;diff=58925"/>
		<updated>2021-05-31T11:03:17Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet/Decision Log to MoodleNet/1.0/Decision Log&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
This page serves as a log of decisions made during the development of the MoodleNet project, along with a brief justification.&lt;br /&gt;
&lt;br /&gt;
* 7 Jan 19 - We&#039;re going to allow users to reset their password via their profile for the 100-user test. The ability to use a &#039;magic link&#039; to their email or change their password directly in their profile may come later. &lt;br /&gt;
* 7 Jan 19 - For the testing instance, we&#039;re planning to use home.moodle.net or moodlers.moodle.net&lt;br /&gt;
* 7 Jan 19 - We&#039;re only going to run one instance for the 100-user test, and then test federation between our team (&#039;dogfooding&#039;) instance and the HQ instance.&lt;br /&gt;
* 7 Jan 19 - We&#039;ve pushed back the initial 100-user test to begin on 28th January, for various internal reasons.&lt;br /&gt;
* 11 Dec 18 - Post-MVP, we&#039;re going to investigate using IPFS (explained [https://achainofblocks.com/2018/10/05/ipfs-interplanetary-file-system-simply-explained/ here]) for storing MoodleNet resources across the federated network. We need a solution that means that collections of resources persist even if an instance is shut down.&lt;br /&gt;
* 11 Dec 18 - After discussion with Martin Dougiamas, MoodleNet instances will have a &#039;switch&#039; that turns federation on and off.&lt;br /&gt;
* 4 Dec 18 - We&#039;re going to split the sign-up process [https://gitlab.com/moodlenet/clients/react/issues/39 into two parts]&lt;br /&gt;
* 20 Nov 18 - After consultation with the Moodle Core team, we&#039;ve decided to keep registrations via moodle.net as-is. This means that we&#039;ll &lt;br /&gt;
** a page at moodle.net informing users about the new platform&lt;br /&gt;
** a link from that page to hub.moodle.org (to access legacy content)&lt;br /&gt;
** a link to a subdomain (TBD) running the new MoodleNet &#039;app&#039;&lt;br /&gt;
* 15 Nov 18 - Keep moodle.net functionality going but redirected to hub.moodle.org. New MoodleNet plugin will replace that functionality (i.e. deprecate moodle.net)&lt;br /&gt;
* 15 Nov 18 - No mandatory tags on collections or resources, but MoodleBot will remind you if you haven&#039;t got language, grade, and subject.&lt;br /&gt;
* 21 Sep 18 - We&#039;ve decided that integration with [https://openbadges.org Open Badges] are going to be out of scope for MVP in January. This is because of the extra work we&#039;d need to do to implement them, and also because Moodle Core should have compatibility with v2.0 of the OB spec by then. We&#039;re fully intending badges to be a part of MoodleNet post-MVP. &lt;br /&gt;
* 20 Sep 18 - We [https://gitlab.com/moodlenet/clients/react/issues/17 reviewed some of the assumptions] we&#039;ve made during the project so far, and documented some decisions around them&lt;br /&gt;
* 17 Sep 18 - We&#039;re dropping the idea of providing [https://blog.moodle.net/2018/ux-milestone-2-screencast-2/ &#039;alt&#039; accounts] as it&#039;s a solution looking for a problem, for the time being. &lt;br /&gt;
* 22 Aug 18 - While whole collections may be imported from MoodleNet into Moodle, when submitting a resource &#039;&#039;from&#039;&#039; Moodle &#039;&#039;to&#039;&#039; MoodleNet, we&#039;ll do this one at a time.&lt;br /&gt;
* 6 Aug 18 - [https://docs.moodle.org/dev/MoodleNet/tech/stack Elixir will be the main programming language] used by MoodleNet&#039;s back-end &lt;br /&gt;
* 13th June 18 - Initial integration will be with MoodleCloud, as that makes it easier in terms of versioning and tightly controlling data flows.&lt;br /&gt;
* 6th June 18 - We&#039;re going to use GitLab now that Microsoft has acquired GitHub.&lt;br /&gt;
* 23rd Apr 18 - Martin has decided we are going with the name &#039;MoodleNet&#039;.&lt;br /&gt;
* Feb 18 - the MVP should be focused on resource curation so that we&#039;re not just dropping people into a social network that doesn&#039;t have a particular purpose&lt;br /&gt;
* 9th Jan 18 - Renaming &#039;News feed&#039; component of project to &#039;Activity feed&#039; to more accurately describe what we&#039;re developing.&lt;br /&gt;
* 3rd Jan 18 - Social sign-in shouldn&#039;t be the &#039;&#039;only&#039;&#039; way to log in to Project MoodleNet ([http://dougbelshaw.com/blog/2018/01/03/identity-on-the-web/ rationale])&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/DPIA&amp;diff=58924</id>
		<title>MoodleNet/DPIA</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/DPIA&amp;diff=58924"/>
		<updated>2021-05-31T11:02:04Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet/DPIA to MoodleNet/1.0/DPIA&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[MoodleNet/1.0/DPIA]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/1.0/DPIA&amp;diff=58923</id>
		<title>MoodleNet/1.0/DPIA</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/1.0/DPIA&amp;diff=58923"/>
		<updated>2021-05-31T11:02:03Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Dougiamas moved page MoodleNet/DPIA to MoodleNet/1.0/DPIA&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Data Protection Impact Assessment ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Current version:&#039;&#039;&#039; 0.1 (June 2019)&lt;br /&gt;
&lt;br /&gt;
According to the UK&#039;s [https://ico.org.uk/for-organisations/guide-to-data-protection/guide-to-the-general-data-protection-regulation-gdpr/accountability-and-governance/data-protection-impact-assessments/ Information Commissioner&#039;s Office] (ICO) a Data Protection Impact Assessment (DPIA) is &amp;quot;a process to help you identify and minimise the data protection risks of a project&amp;quot;. Under the terms of the EU&#039;s [https://en.wikipedia.org/wiki/General_Data_Protection_Regulation General Data Protection Regulation] (GDPR) is mandatory to create a DPIA &amp;quot;for processing that is likely to result in a high risk to individuals&amp;quot;. However, it is also &amp;quot;good practice to do a DPIA for any other major project which requires the processing of personal data&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As a result, this DPIA for MoodleNet aims to:&lt;br /&gt;
&lt;br /&gt;
* describe the nature, scope, context and purposes of the processing&lt;br /&gt;
* assess necessity, proportionality and compliance measures&lt;br /&gt;
* identify and assess risks to individuals&lt;br /&gt;
* identify any additional measures to mitigate those risks&lt;br /&gt;
&lt;br /&gt;
== Identify the need for a DPIA ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is a social network for educators. They can engage in discussions and share resources with one another. What makes MoodleNet different is that it is a federated network, so individuals and organisations can install and set up their own ‘instance’. &lt;br /&gt;
&lt;br /&gt;
Moodle HQ (Moodle Pty Ltd) will run a special instance of MoodleNet that indexes some of the data shared from the federated instances who wish to participate. There is also a class of information that is ‘private’ and isn’t accessed by Moodle HQ. The instance of MoodleNet run by Moodle HQ (the “Mothership”) will store data such as metadata about groups, resources, and public user profiles from third-party instances. This will be covered under a ‘ Terms of Service’ agreement between Moodle HQ and the entity operating the instance.&lt;br /&gt;
Moodle HQ will also run one or more of its own instances, each of which will store personal data related to its users (such as contact details and discussions). This will be covered under a user agreement (Code of Conduct and Privacy Policy).&lt;br /&gt;
&lt;br /&gt;
We believe that a DPIA is necessary because we are processing personal data at scale, including processing sensitive personal data. Moodle is committed to privacy-enhancing technology, which give its users choices about their personal data, and process that data only insofar as is necessary and proportionate for the services offered. &lt;br /&gt;
&lt;br /&gt;
Further details may be found at: https://moodle.com/moodlenet&lt;br /&gt;
&lt;br /&gt;
== Describe the processing ==&lt;br /&gt;
&lt;br /&gt;
=== Nature ===&lt;br /&gt;
MoodleNet is first and foremost a software application which allows for the creation of a federated network, as shown in the diagram below. An organisation can install a MoodleNet instance to allow their users to share resources and ideas with one another, but also potentially with the users of any other MoodleNet instance. A MoodleNet instance consists of a &#039;database&#039;, a ‘backend’ and ‘frontend’ which are typically deployed via Docker containers on servers hosted either on-site or in a data centre. &lt;br /&gt;
&lt;br /&gt;
The main uses of MoodleNet are:&lt;br /&gt;
* Joining communities of users&lt;br /&gt;
* Curating educational resources into ‘collections’&lt;br /&gt;
* Engaging in discussions    &lt;br /&gt;
&lt;br /&gt;
Each instance of MoodleNet can be run independently, and can (optionally) connect to a service run by Moodle HQ ( which we refer to as the ‘Mothership’). This will be separate from any regular MoodleNet instances run by Moodle HQ to which end users may sign up.&lt;br /&gt;
&lt;br /&gt;
The administrator of a MoodleNet instance may request a Mothership API key, subject to agreeing to Terms of Service. This does two things:&lt;br /&gt;
&lt;br /&gt;
# Allows the HQ Mothership to receive public metadata from the instance (relating to communities, collections, resources, and user profiles) and store that in a search index&lt;br /&gt;
# Provides users of the instance the ability to search across the federated network, meaning they can discover communities, collections, users, and content from other instances. &lt;br /&gt;
&lt;br /&gt;
The HQ Mothership stores a copy of the metadata from the federated instances which are connected via an API key. Search results provided to connected instances link directly to content on the originating federated instance.&lt;br /&gt;
&lt;br /&gt;
Although a lot of the richness of search will come through tagging, we will also index public fields from user profiles. This is to surface the most relevant information to users.&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet_architecture_data_flows.png]]&lt;br /&gt;
&lt;br /&gt;
The HQ Mothership indexes the public data provided by connected instances, making it quickly and easily searchable (using Algolia, a third party search engine service). This data includes information such as username, profile images, location, comments, and communities joined.&lt;br /&gt;
&lt;br /&gt;
Even instances that are &#039;&#039;not&#039;&#039; connected to the HQ Mothership are nevertheless connected to one another thanks to the ActivityPub protocol. In fact, whether connected to the HQ Mothership or not, because of the way ActivityPub works, they are potentially connected to &#039;&#039;any&#039;&#039; other ActivityPub-enabled server (including servers running software other than MoodleNet).&lt;br /&gt;
&lt;br /&gt;
[[File:ActivityPub-tutorial-image.png]]&lt;br /&gt;
&lt;br /&gt;
MoodleNet will carefully differentiate between structured personal data fields and data that the individual contributes as part of their participation within communities. For example, users will be able to delete their account at any time. However, deleting their account will not delete any contributions they may have made to collections of resources. &lt;br /&gt;
&lt;br /&gt;
To explain further, there are two main types of contributions to MoodleNet: adding resources, and adding comments. While comments are text-based and always attributed to a user, adding resources can happen in one of two ways:&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;URL&#039;&#039;&#039; - the user points to a resource which is available on the open web. The metadata from the site hosting the resource is automatically pulled in by MoodleNet.&lt;br /&gt;
# &#039;&#039;&#039;Upload&#039;&#039;&#039; - the user uploads a resource and adds it to a collection using an open license. This is a similar process to uploading resources to Wikimedia Commons, the process for which will inform our work and which is detailed here: https://commons.wikimedia.org/wiki/Commons:Project_scope/Summary &lt;br /&gt;
&lt;br /&gt;
The highest risk for users could arise if they are unaware that comments they add in discussion areas on one instance of MoodleNet are potentially viewable and storable by any application or server running the ActivityPub protocol (e.g. Mastodon, Pleroma, Osada). We will take steps to make sure this is clear to users, both through the user agreement but also through the visual and textual elements in the User Interface of the application.&lt;br /&gt;
&lt;br /&gt;
Our proposed moderation flow for content or metadata on MoodleNet is outlined in the diagram below:&lt;br /&gt;
&lt;br /&gt;
[[File:MoodleNet_moderation_diagram.png]]&lt;br /&gt;
&lt;br /&gt;
If a user ‘flags’ a resource, collection, comment, or profile, this is reviewed by the moderators of the relevant community. They may choose to take action, which could include removing content and/or warning a user. Ultimately, moderators may choose to ban a user from a community.&lt;br /&gt;
&lt;br /&gt;
Should a community not be moderated effectively, users have the option of flagging that to the instance administrator. They can review the complaint and choose to warn the moderators, warn or ban the offending users from the instance, directly remove content, or close the community.&lt;br /&gt;
&lt;br /&gt;
If an entire instance is problematic, users of other instances may complain (preferably through their instance admin) to Moodle HQ, who runs the ‘HQ Mothership’. Moodle HQ will review the complaint and, if appropriate, issue a warning to the admin of the problematic instance. Should the problem persist, or if the initial complaint was serious enough, Moodle HQ would revoke the instance’s API key and delete its copies of data from that instance from the HQ Mothership (including any search indexes stored via third-party services such as Algolia).&lt;br /&gt;
&lt;br /&gt;
While this would not fully shut down the instance, it would stop being included in the search results on other MoodleNet instances. Moodle HQ does not process any of the data from federated instances without an API key, including those instances whose API key has been revoked.&lt;br /&gt;
&lt;br /&gt;
=== Scope ===&lt;br /&gt;
&lt;br /&gt;
For users of Moodle HQ&#039;s instance(s) of MoodleNet, we will be collecting personal data, including: name, location, resources uploaded, comments, browser version, and IP address. This does not include criminal offence data, but may include special categories such as political beliefs and accessibility requirements. We could also infer ethnicity through avatars, including photographs, that users choose to represent themselves. This would be as a by-product of using the system, through optional rather than mandatory activity (e.g. tagging, photo-upload, discussion replies). &lt;br /&gt;
&lt;br /&gt;
We will check the age and jurisdiction of a user attempting to create an account, and deny the ability to create an account to those under the age of majority in their jurisdiction. In our user agreement we will specify that users must collect valid consent from individuals whose data is being processed.&lt;br /&gt;
&lt;br /&gt;
Users will be able to register from anywhere in the world, on one or more of many federated MoodleNet instances operated by third parties. These may be hosted in any jurisdiction, including the European Union. As a result, MoodleNet instances are subject to the GDPR. A user’s location may be inferred from their IP address, but they are free to choose whether or not to enter a city-based location in their profile. &lt;br /&gt;
&lt;br /&gt;
One thing we need to be careful of is the possibility of identifying location or ethnicity based on the use of minority languages. For example, the community have already localised the testing version of MoodleNet into the Basque language, which is spoken by relatively few people, and mainly in a particular geographical region. Likewise, we may identify users with special needs through accessibility settings and recognising that they are using assistive technologies. &lt;br /&gt;
&lt;br /&gt;
While users will have the ability to hide information about themselves on their profile so that only they can see it, we are aware that this only hides information from other users, not from the operator of the instance. As a result, we will add a statement in the user agreement making users aware about the way that they might, implicitly and explicitly, reveal sensitive information such as their preferences, any disabilities, and ethnicity or location data. To make this clear we will use straightforward language and diagrams. &lt;br /&gt;
&lt;br /&gt;
We will be continuously collecting data made public by users for as long as they have an account on a federated instance. We will initially be collecting data on hundreds of users, but this is likely to increase to at least tens of thousands of users. &lt;br /&gt;
&lt;br /&gt;
=== Context ===&lt;br /&gt;
&lt;br /&gt;
All users of Moodle HQ&#039;s instance(s) of MoodleNet will be above the age of digital consent according to their jurisdiction. As part of our user agreement, we are using a Code of Conduct to govern Moodle HQ&#039;s relationship with users, interactions amongst users, and users&#039; contributions to MoodleNet, as detailed at https://www.contributor-covenant.org &lt;br /&gt;
We are not targeting vulnerable groups, we are using data in a way that users would expect, and are not aware of any issues of public concern in this area. Users are registering on a voluntary basis.&lt;br /&gt;
&lt;br /&gt;
Our relationship with users on instances that Moodle HQ host is:&lt;br /&gt;
&lt;br /&gt;
* Data Controller&lt;br /&gt;
* Data Processor&lt;br /&gt;
&lt;br /&gt;
On instances &#039;&#039;not&#039;&#039; hosted by Moodle HQ, we provide the HQ Mothership API service that indexes data as well as provides search and discovery across federated instances. In this case, we index public content from other instances to allow this to happen. Our relationship with instance administrators is therefore:&lt;br /&gt;
&lt;br /&gt;
* Joint Data Controller &#039;&#039;(in respect of certain elements of personal data made public by users which Moodle HQ makes searchable across the federated instances connected to the Mothership)&#039;&#039;&lt;br /&gt;
* Data Processor&lt;br /&gt;
&lt;br /&gt;
Instance administrators act as the Data Controller, and can request Moodle HQ to delete personal data on the data subject from the HQ Mothership.&lt;br /&gt;
&lt;br /&gt;
As mentioned above and in reference to the diagram, contributions of content that do not include personal data will remain in MoodleNet after a user deletes their account. This is consistent with the open licenses we will use for uploaded resources and our user agreement.&lt;br /&gt;
&lt;br /&gt;
=== Purposes ===&lt;br /&gt;
&lt;br /&gt;
We are processing personal data for the purposes of identification on a social network. We envisage that this will lead to increased trust and sharing of resources and ideas amongst the educators using federated MoodleNet instances. Users will be able to identify one another, talk about shared interests and goals, and both link to and upload resources that will help their communities.&lt;br /&gt;
&lt;br /&gt;
Moodle HQ gains from this by building something that fits with our values, but also provides a vehicle to complement and point towards our own paid offerings (e.g. MoodleCloud), as well as to our Partners, from whom we receive a share of their revenue.&lt;br /&gt;
&lt;br /&gt;
We are attempting to collect the minimum amount of data to create a federated network of MoodleNet instances. To enable search across the instances connected to the HQ Mothership, we must act as Joint Data Controllers with administrators of those federated instances for the data elements over which we exercise independent control. In addition, we are Data Processors for the administrators of any federated instances, as we are processing data from those federated instances on their behalf, as part of the service offered to their users by them as Data Controllers. &lt;br /&gt;
&lt;br /&gt;
== Assess necessity and proportionality ==&lt;br /&gt;
&lt;br /&gt;
We are gaining the consent of users to process their personal data when they register on one of the instances of MoodleNet which are connected with the HQ Mothership. They will agree with a privacy notice, we will capture the minimum amount of personal data required, and users will be able to access, rectify, export, and delete this data.&lt;br /&gt;
&lt;br /&gt;
As a federated social network, our aim is to process only the data that users have made publicly available, and which is necessary to meet the aims of MoodleNet. Namely, we want users to be able to identify one another and indicate affinity based on factors such as geographical location and interests. Other than a controlled taxonomy for parts of the tagging system, we are allowing users to add free text into these fields, thus allowing them to be pseudo-anonymous. &lt;br /&gt;
&lt;br /&gt;
If we were building a centralised system, we would potentially have access to all user data, including that shared (as far as the user is concerned) ‘privately’. By creating a federated network, users can choose to join an instance they trust, or indeed run their own. &lt;br /&gt;
&lt;br /&gt;
Built into MoodleNet will be the ability to request that data be deleted from other instances after being deleted from the user’s ‘home’ instance. By default, MoodleNet servers will comply with this request, but we cannot control whether third-party servers comply with the request. We will work with the main ActivityPub-compatible social networking apps to encourage them to comply with these requests by default.&lt;br /&gt;
&lt;br /&gt;
== Consultation process ==&lt;br /&gt;
&lt;br /&gt;
We have tested MoodleNet with around 250 volunteers to ascertain both the value proposition and to ensure that they are happy with the product. We collected the minimum amount of personal data in order to facilitate the successful use of the service.&lt;br /&gt;
&lt;br /&gt;
In order to ensure that MoodleNet is as secure and privacy-respecting as possible, we are implementing industry best practices. This will include starting a ‘bug bounty’ program specifically focused on security and privacy. To enable this we will use a crowdsourcing platform that gives us access to security and privacy researchers and ethical hackers.  &lt;br /&gt;
The MoodleNet team works closely with Moodle’s Privacy Officer and DPO to ensure that the procedures we are following start from a ‘privacy by design’ point of view. As we implement MoodleNet, the team will continue to meet regularly with the Privacy Officer and DPO to inform upcoming changes and decisions.&lt;br /&gt;
&lt;br /&gt;
In addition, we plan to share this DPIA with the Moodle community for their feedback, as we intend to be as transparent as possible with this project. Anyone may give feedback via the following methods: &lt;br /&gt;
&lt;br /&gt;
* Moodle.org forum: https://moodle.org/mod/forum/view.php?id=8352&lt;br /&gt;
* Email MoodleNet team: moodlenet-moderators@moodle.com&lt;br /&gt;
* Fediverse: https://mastodon.social/@moodlenet&lt;br /&gt;
* Twitter: https://twitter.com/moodlenet&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58921</id>
		<title>MoodleNet</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=58921"/>
		<updated>2021-05-31T10:59:08Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Moodlenet-logo.png|400px]]&lt;br /&gt;
&lt;br /&gt;
== What is MoodleNet? ==&lt;br /&gt;
&lt;br /&gt;
MoodleNet is our new social network to share and curate open educational resources with educators world-wide.  It is integrated closely with Moodle LMS and Moodle Workplace to make resources easy to find and use, but can be useful even if you don&#039;t use Moodle LMS. MoodleNet is also intended as a way to build your profile as an educator.&lt;br /&gt;
&lt;br /&gt;
Importantly, MoodleNet is designed to be a federated, flexible Open Education Technology that is not controlled by a single entity, or subject to a single point of failure.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Current status ==&lt;br /&gt;
&#039;&#039;Last updated: 31 May 2021&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
MoodleNet 1.x was abandoned by the team in 2021 because it was heading down the wrong path.  The project was recently rebooted (January 2021) with a new team, new architecture and a simpler new design.&lt;br /&gt;
&lt;br /&gt;
== Roadmap ==&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;15 August 2021&#039;&#039;&#039; - MVP for wider community testing and feedback&lt;br /&gt;
* &#039;&#039;&#039;31 August 2021&#039;&#039;&#039; - Beta release , feature complete for 2.0 release.&lt;br /&gt;
* &#039;&#039;&#039;15 September 2021&#039;&#039;&#039; - 2.0 release!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Important links ==&lt;br /&gt;
&lt;br /&gt;
* [https://gitlab.com/moodlenet Code repository]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=8726 MoodleNet news and discussion]&lt;br /&gt;
&lt;br /&gt;
== Archive ==&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/inspiration Inspiration]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-research Other research]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-consultancy MoodleNet consultancy]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Copyright_Directive European Copyright Directive]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/DPIA Data Protection Impact Assessment]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Testing Beta testing]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Decision_Log Decision log]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[es:MoodleNet]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet/Security&amp;diff=58200</id>
		<title>MoodleNet/Security</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet/Security&amp;diff=58200"/>
		<updated>2021-01-13T07:39:43Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Replaced content with &amp;quot;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]  ----  Deleted&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Deleted&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Roadmap&amp;diff=57709</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Roadmap&amp;diff=57709"/>
		<updated>2020-07-15T06:15:56Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Last Updated: 15 July 2020 Q3&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
The Moodle Project is designed to have a positive effect on the world by supporting and empowering the educators who are teaching students in all sectors, in all countries.  &lt;br /&gt;
&lt;br /&gt;
To do this, our team at Moodle HQ looks to the world, talks with our community, and creates solutions in the forms of products that fit our values of &#039;&#039;&#039;education&#039;&#039;&#039;, &#039;&#039;&#039;openness&#039;&#039;&#039;, &#039;&#039;&#039;respect&#039;&#039;&#039;, &#039;&#039;&#039;integrity&#039;&#039;&#039; and &#039;&#039;&#039;innovation&#039;&#039;&#039;. &lt;br /&gt;
&lt;br /&gt;
This document summarises, for a broad audience, the best current plans on the future technical development of the Moodle’s open source learning platform, consisting of Moodle LMS, Moodle Workplace LMS, MoodleCloud, MoodleNet, Moodle Apps, and Moodle Educator Certificates.&lt;br /&gt;
&lt;br /&gt;
We publish Roadmap updates such as this one every quarter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where this roadmap comes from==&lt;br /&gt;
&lt;br /&gt;
Proposals for improvements and new features come from a variety of different places.  &lt;br /&gt;
&lt;br /&gt;
Feedback from the community is extremely important and you can reach us by&lt;br /&gt;
* creating new issues on [http://tracker.moodle.org tracker], &lt;br /&gt;
* joining the [https://moodleassociation.org/ Moodle Users Association] to vote on a new project for each release, &lt;br /&gt;
* discussing your ideas on the [https://moodle.org/forums forums], &lt;br /&gt;
* creating new solutions as a plugin in the [https://moodle.org/plugins Moodle Plugins directory], &lt;br /&gt;
* or meeting us in person at one of our [https://moodle.com/events/ MoodleMoots]!&lt;br /&gt;
&lt;br /&gt;
Moodle also has an extensive network of [https://moodle.com/partners Moodle Partners]. Moodle Partners are service providers that are certified by Moodle HQ to provide high quality Moodle services for schools, institutions and organisations. We work closely with our partners to determine the needs of Moodle Users and improve the platform.&lt;br /&gt;
&lt;br /&gt;
Our Roadmap is built via our [[Roadmap process]]. This process is continuously evolving but it always seeks to involve all our key stakeholders - students, teachers, admins, institutions, and of course our partners and supporters.&lt;br /&gt;
&lt;br /&gt;
= The big picture =&lt;br /&gt;
&lt;br /&gt;
Working on the Moodle learning platform involves millions of moving parts, and every release generally includes hundreds of improvements.  However, there are &#039;&#039;&#039;four main goals&#039;&#039;&#039; that we are focussing on for the next two years:&lt;br /&gt;
&lt;br /&gt;
=== User experience and flow ===&lt;br /&gt;
&lt;br /&gt;
The entire user experience from onboarding, into daily teaching/learning and expert customisation of Moodle is the core value of what makes Moodle useful or not in the real world, in fully online and blended modes.&lt;br /&gt;
&lt;br /&gt;
While we’re working on hundreds of smaller, annoying issues, we are also doing some major re-thinking around what an LMS should be in the next decade and beyond as a tool to empower educators and learners.&lt;br /&gt;
&lt;br /&gt;
=== Enabling all our developers ===&lt;br /&gt;
&lt;br /&gt;
Our significant community of engaged developers are an amazing group of over 1000 people - many of them make a living being part of the Moodle community.&lt;br /&gt;
&lt;br /&gt;
We are of course working on ways to make Moodle programming easier and better, with better training and support as well as improved APIs, plugins, integrations and support for modern technologies.&lt;br /&gt;
&lt;br /&gt;
However, a particularly exciting initiative is the new Moodle Plugins Service, due in 2021, which will provide an “app store” experience on which all developers can build financial sustainability for their work, while teachers will have easier access to use hundreds of new plugins in their courses via the web interface, without needing to convince their admins to install code. This will help the entire plugins ecosystem.&lt;br /&gt;
&lt;br /&gt;
===Better integrations between Moodle products===&lt;br /&gt;
&lt;br /&gt;
The current Moodle products already integrate with each other, of course, but there is much more to be done to make them work together more seamlessly, as part of one platform, so that our users have a better experience and also so that they become more aware of solutions to their problems.&lt;br /&gt;
&lt;br /&gt;
=== Better integration with the world ===&lt;br /&gt;
&lt;br /&gt;
Moodle is never used alone, and it is a part of many ecosystems at many levels. We must connect to all kinds of other systems, we must of course comply with new legislation such as the GDPR, Accessibility and much more.&lt;br /&gt;
&lt;br /&gt;
In particular though, we are committed to helping to promote [https://openedtech.global/ &amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Open EdTech&amp;lt;/span&amp;gt;] and to work closely with qualified Open EdTech products and major stakeholders to design and build an open architecture for a long-term future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Roadmap timeline =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &#039;&#039;&#039;2020&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle LMS&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;MoodleCloud&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;MoodleNet&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;Launch of new Moodle app plans&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Launch of Workplace hosting&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Free trials&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
LLTS (Long Long Term Support)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Create H5P content&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
MoodleNet&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Activity chooser&lt;br /&gt;
&lt;br /&gt;
Participants filters (MUA)&lt;br /&gt;
&lt;br /&gt;
Accessibility&lt;br /&gt;
&lt;br /&gt;
Safe Exam Browser&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Appointments&lt;br /&gt;
&lt;br /&gt;
Data Importers and exporters&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Text editor draft autosave&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updates:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle LMS 3.9 compatibility&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Moodle Workplace 3.9 compatibility&lt;br /&gt;
|&lt;br /&gt;
Improved connections with other Moodle products&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Self-service for renames and restores&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 1.0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Integrates to Moodle 3.9 and later&lt;br /&gt;
&lt;br /&gt;
Moderation&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Federation&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
HQ-run home instance&lt;br /&gt;
&lt;br /&gt;
GDPR compliance&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Themeable&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;MEC 2020 launch&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;6 courses covering all 22 competencies&lt;br /&gt;
&lt;br /&gt;
Translated into multiple languages&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Minor release(s)&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Tenant-shared learning&lt;br /&gt;
| &#039;&#039;&#039;Notifications of new grades&lt;br /&gt;
&lt;br /&gt;
Improved connections with other products&lt;br /&gt;
| New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New plans&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Updates:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Simplified signup and upgrades&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Minor release(s)&lt;br /&gt;
| Report Builder improvements&lt;br /&gt;
| &#039;&#039;&#039;Functionality gaps for students&lt;br /&gt;
&lt;br /&gt;
UX improvements&lt;br /&gt;
| Improvements based on customer needs&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;MEC Direct Release&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;MEC licensing for large institutions&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2021&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle LMS&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MoodleCloud&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MoodleNet&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Minor release(s)&lt;br /&gt;
| &#039;&#039;&#039;Dashboards&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Minor release(s)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Moodle Plugins Service Soft Launch&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Other certifications&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Minor release(s)&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Workplace features:&amp;lt;br /&amp;gt;&lt;br /&gt;
- Certificates&amp;lt;br /&amp;gt;&lt;br /&gt;
- Report Builder&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
UX navigation&lt;br /&gt;
&lt;br /&gt;
UX biggest pains&lt;br /&gt;
&lt;br /&gt;
UX consistency via component library&lt;br /&gt;
&lt;br /&gt;
Information flow and task management&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle LMS 4.0 compatibility&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Moodle Workplace 4.0 compatibility&lt;br /&gt;
&lt;br /&gt;
Classroom tools with friendly UX&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2022&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle LMS&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MoodleCloud&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;MoodleNet&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Notes on some of these major release dates: ==&lt;br /&gt;
&lt;br /&gt;
===Moodle 4.0 in November 2021 ===&lt;br /&gt;
&lt;br /&gt;
Normally Moodle LMS major releases are every 6 months, in May and November.&lt;br /&gt;
&lt;br /&gt;
However, for our very large new releases such as 1.0, 2.0, 3.0 and now 4.0, we often take longer so that we can tackle more significant chunks of important core work, giving us the opportunity sometimes to make more serious changes to UX or architecture.&lt;br /&gt;
&lt;br /&gt;
There are a lot of ideas around for 4.0 - we will be relying on our new UX team to organise and prioritise a lot of it during the next 6 months.&lt;br /&gt;
&lt;br /&gt;
=== Moodle 3.9 release in June 2020 ===&lt;br /&gt;
&lt;br /&gt;
In support of a longer release timeframe for Moodle 4.0, we have decided to release Moodle 3.9 in June.&lt;br /&gt;
&lt;br /&gt;
The extra month will give us time to bring in a number of extra items in support of Moodle’s other products, which are in addition to the planned features for the 3.9 release.&lt;br /&gt;
&lt;br /&gt;
It will also allow us to include as many community contributions as possible as we work towards the release date.&lt;br /&gt;
&lt;br /&gt;
* Code freeze (no new features accepted): &#039;&#039;&#039;4th May 2020&#039;&#039;&#039;&lt;br /&gt;
* QA cycle (start of QA testing): &#039;&#039;&#039;11th May 2020&#039;&#039;&#039;&lt;br /&gt;
* Scheduled release date (once QA passed): &#039;&#039;&#039;15th June 2020&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Past releases=&lt;br /&gt;
&lt;br /&gt;
See our [[Releases]] page for information about past releases.&lt;br /&gt;
&lt;br /&gt;
After Moodle 2.0 we switched to time-based releases rather than feature-based releases (see our [https://docs.moodle.org/dev/Process development process]). Because of this, the details above on future releases are an indication of current priorities only, and are targeted to be released in the upcoming releases. Anything not ready by the next release date will generally be pushed to the following major release.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Releases]] - versions of Moodle that have already been released&lt;br /&gt;
* https://docs.moodle.org/dev/Releases#General_release_calendar Key dates relating to future releases. &lt;br /&gt;
&lt;br /&gt;
[[es:Plan de desarrollo]] &lt;br /&gt;
[[fr:Planification]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Roadmap_process&amp;diff=57070</id>
		<title>Roadmap process</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Roadmap_process&amp;diff=57070"/>
		<updated>2020-03-13T07:53:54Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* Roadmap Process */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Roadmap Process ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
A new process is being finalised.    It will be here soon.  &lt;br /&gt;
&lt;br /&gt;
Thank you for your patience.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Roadmap&amp;diff=57069</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Roadmap&amp;diff=57069"/>
		<updated>2020-03-13T07:52:36Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;Last Updated: 13 March 2020 Q1&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
The Moodle Project is designed to have a positive effect on the world by supporting and empowering the educators who are teaching students in all sectors, in all countries.  &lt;br /&gt;
&lt;br /&gt;
To do this, our team at Moodle HQ looks to the world, talks with our community, and creates solutions in the forms of products that fit our values of education, openness, respect, integrity and innovation. &lt;br /&gt;
&lt;br /&gt;
This document summarises, for a broad audience, the best current plans on the future technical development of the Moodle’s open source learning platform, consisting of Moodle LMS, Moodle Workplace LMS, MoodleCloud, MoodleNet, Moodle Apps, and Moodle Educator Certificates.&lt;br /&gt;
&lt;br /&gt;
We publish Roadmap updates such as this one every quarter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where this roadmap comes from==&lt;br /&gt;
&lt;br /&gt;
Proposals for improvements and new features come from a variety of different places.  &lt;br /&gt;
&lt;br /&gt;
Feedback from the community is extremely important and you can reach us by&lt;br /&gt;
* creating new issues on [http://tracker.moodle.org tracker], &lt;br /&gt;
* joining the [https://moodleassociation.org/ Moodle User Association] to vote on a new project for each release, &lt;br /&gt;
* discussing your ideas on the [https://moodle.org/forums forums], &lt;br /&gt;
* creating new solutions as a plugin in the [https://moodle.org/plugins Moodle Plugins directory], &lt;br /&gt;
* or meeting us in person at one of our [https://moodle.com/events/ MoodleMoots]!&lt;br /&gt;
&lt;br /&gt;
Moodle also has an extensive network of [https://moodle.com/partners Moodle Partners]. Moodle Partners are service providers that are certified by Moodle HQ to provide high quality Moodle services for schools, institutions and organisations. We work closely with our partners to determine the needs of Moodle Users and improve the platform.&lt;br /&gt;
&lt;br /&gt;
Our Roadmap is built via our [http://docs.moodle.org/dev/Roadmap_process &amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Roadmap Process&amp;lt;/span&amp;gt;]. This process is continuously evolving but it always seeks to involve all our key stakeholders - students, teachers, admins, institutions, and of course our partners and supporters.&lt;br /&gt;
&lt;br /&gt;
= The big picture =&lt;br /&gt;
&lt;br /&gt;
Working on the Moodle learning platform involves millions of moving parts, and every release generally includes hundreds of improvements.  However, there are &#039;&#039;&#039;four main goals&#039;&#039;&#039; that we are focussing on for the next two years:&lt;br /&gt;
&lt;br /&gt;
=== User experience and flow ===&lt;br /&gt;
&lt;br /&gt;
The entire user experience from onboarding, into daily teaching/learning and expert customisation of Moodle is the core value of what makes Moodle useful or not in the real world, in fully online and blended modes.&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
While we’re working on hundreds of smaller, annoying issues, we are also doing some major re-thinking around what an LMS should be in the next decade and beyond as a tool to empower educators and learners.&lt;br /&gt;
&lt;br /&gt;
=== Enabling all our developers ===&lt;br /&gt;
&lt;br /&gt;
Our significant community of developers are an amazing group of over 1000 people - many of them make a living being part of the Moodle community.&lt;br /&gt;
&lt;br /&gt;
We are of course working on ways to make Moodle programming easier and better, with better training and support as well as improved APIs, plugins, integrations and support for modern technologies.&lt;br /&gt;
&lt;br /&gt;
However, a particularly exciting initiative is the new Moodle Plugins Service, due in 2021, which will provide an “app store” experience on which all developers can build financial sustainability for their work, while teachers will have easier access to use hundreds of new plugins in their courses via the web interface, without needing to convince their admins to install code. This will help the entire plugins ecosystem.&lt;br /&gt;
&lt;br /&gt;
===Better integrations between Moodle products===&lt;br /&gt;
&lt;br /&gt;
The current Moodle products already integrate with each other, of course, but there is much more to be done to make them work together more seamlessly, as part of one platform, so that our users have a better experience and also so that they become more aware of solutions to their problems.&lt;br /&gt;
&lt;br /&gt;
=== Better integration with the world ===&lt;br /&gt;
&lt;br /&gt;
Moodle is never used alone, and it is a part of many ecosystems at many levels. We must connect to all kinds of other systems, we must of course comply with new legislation such as the GDPR, Accessibility and much more.&lt;br /&gt;
&lt;br /&gt;
In particular though, we are committed to helping to promote [https://openedtech.global/ &amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Open EdTech&amp;lt;/span&amp;gt;] and to work closely with qualified Open EdTech products and major stakeholders to design and build an open architecture for a long-term future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Roadmap timeline =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &#039;&#039;&#039;2020&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
LMS&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Cloud&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Net&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;Launch of new Moodle app plans&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Launch of Workplace hosting&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Free trials&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
LLTS&amp;lt;ref&amp;gt;Long Long Term Support&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Create H5P content&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
MoodleNet&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Activity chooser&lt;br /&gt;
&lt;br /&gt;
Participants filters (MUA)&lt;br /&gt;
&lt;br /&gt;
Accessibility&lt;br /&gt;
&lt;br /&gt;
Safe Exam Browser&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Appointments&lt;br /&gt;
&lt;br /&gt;
Data Importers and exporters&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Text editor draft autosave&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updates:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle LMS 3.9 compatibility&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Moodle Workplace 3.9 compatibility&lt;br /&gt;
|&lt;br /&gt;
Improved connections with other Moodle products&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Self-service for renames and restores&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 1.0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Integrates to Moodle 3.9 and later&lt;br /&gt;
&lt;br /&gt;
Moderation&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Federation&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
HQ-run home instance&lt;br /&gt;
&lt;br /&gt;
GDPR compliance&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Themeable&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;MEC 2020 launch&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;6 courses covering all 22 competencies&lt;br /&gt;
&lt;br /&gt;
Translated into multiple languages&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tenant-shared learning&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Notifications of new grades&lt;br /&gt;
&lt;br /&gt;
Improved connections with other products&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New plans&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Updates:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Simplified signup and upgrades&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Report Builder improvements&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.2&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Functionality gaps for students&lt;br /&gt;
&lt;br /&gt;
UX improvements&lt;br /&gt;
| Improvements based on customer needs&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;MEC Direct Release&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;MEC licensing for large institutions&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2021&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
LMS&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Cloud&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Net&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.3&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Dashboards&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Plugins Service Soft Launch&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Other certifications&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Workplace features:&amp;lt;br /&amp;gt;&lt;br /&gt;
- Certificates&amp;lt;br /&amp;gt;&lt;br /&gt;
- Report Builder&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
UX navigation&lt;br /&gt;
&lt;br /&gt;
UX biggest pains&lt;br /&gt;
&lt;br /&gt;
UX consistency via component library&lt;br /&gt;
&lt;br /&gt;
Information flow and task management&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle LMS 4.0 compatibility&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Moodle Workplace 4.0 compatibility&lt;br /&gt;
&lt;br /&gt;
Classroom tools with friendly UX&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2022&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
LMS&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Cloud&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Net&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Notes on some of these major release dates: ==&lt;br /&gt;
&lt;br /&gt;
===Moodle 4.0 in November 2021 ===&lt;br /&gt;
&lt;br /&gt;
Normally Moodle LMS major releases are every 6 months, in May and November.&lt;br /&gt;
&lt;br /&gt;
However, for our very large new releases such as 1.0, 2.0, 3.0 and now 4.0, we often take longer so that we can tackle more significant chunks of important core work, giving us the opportunity sometimes to make more serious changes to UX or architecture.&lt;br /&gt;
&lt;br /&gt;
There are a lot of ideas around for 4.0 - we will be relying on our new UX team to organise and prioritise a lot of it during the next 6 months.&lt;br /&gt;
&lt;br /&gt;
=== Moodle 3.9 release in June 2020 ===&lt;br /&gt;
&lt;br /&gt;
In support of a longer release timeframe for Moodle 4.0, we have decided to release Moodle 3.9 in June.&lt;br /&gt;
&lt;br /&gt;
The extra month will give us time to bring in a number of extra items in support of Moodle’s other products, which are in addition to the planned features for the 3.9 release.&lt;br /&gt;
&lt;br /&gt;
It will also allow us to include as many community contributions as possible as we work towards the release date.&lt;br /&gt;
&lt;br /&gt;
* Code freeze (no new features accepted): &#039;&#039;&#039;6th April 2020&#039;&#039;&#039;&lt;br /&gt;
* QA cycle (start of QA testing): &#039;&#039;&#039;13th April 2020&#039;&#039;&#039;&lt;br /&gt;
* Scheduled release date (once QA passed): &#039;&#039;&#039;11th May 2020&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Past releases=&lt;br /&gt;
&lt;br /&gt;
See our [[Releases]] page for information about past releases.&lt;br /&gt;
&lt;br /&gt;
After Moodle 2.0 we switched to time-based releases rather than feature-based releases (see our [https://docs.moodle.org/dev/Process development process]). Because of this, the details above on future releases are an indication of current priorities only, and are targeted to be released in the upcoming releases. Anything not ready by the next release date will generally be pushed to the following major release.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Releases]] - versions of Moodle that have already been released&lt;br /&gt;
* https://docs.moodle.org/dev/Releases#General_release_calendar Key dates relating to future releases. &lt;br /&gt;
&lt;br /&gt;
[[es:Plan de desarrollo]] &lt;br /&gt;
[[fr:Planification]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Roadmap&amp;diff=57068</id>
		<title>Roadmap</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Roadmap&amp;diff=57068"/>
		<updated>2020-03-13T07:45:09Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Last Updated: 3 March 2020 Q1&lt;br /&gt;
&lt;br /&gt;
= Introduction =&lt;br /&gt;
&lt;br /&gt;
The Moodle Project is designed to have a positive effect on the world by supporting and empowering the educators who are teaching students in all sectors, in all countries.  &lt;br /&gt;
&lt;br /&gt;
To do this, our team at Moodle HQ looks to the world, talks with our community, and creates solutions in the forms of products that fit our values of education, openness, respect, integrity and innovation. &lt;br /&gt;
&lt;br /&gt;
This document summarises, for a broad audience, the best current plans on the future technical development of the Moodle’s open source learning platform, consisting of Moodle LMS, Moodle Workplace LMS, MoodleCloud, MoodleNet, Moodle Apps, and Moodle Educator Certificates.&lt;br /&gt;
&lt;br /&gt;
We publish Roadmap updates such as this one every quarter.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Where this roadmap comes from==&lt;br /&gt;
&lt;br /&gt;
Proposals for improvements and new features come from a variety of different places.  &lt;br /&gt;
&lt;br /&gt;
Feedback from the community is extremely important and you can reach us by&lt;br /&gt;
* creating new issues on [http://tracker.moodle.org tracker], &lt;br /&gt;
* joining the [https://moodleassociation.org/ Moodle User Association] to vote on a new project for each release, &lt;br /&gt;
* discussing your ideas on the [https://moodle.org/forums forums], &lt;br /&gt;
* creating new solutions as a plugin in the [https://moodle.org/plugins Moodle Plugins directory], &lt;br /&gt;
* or meeting us in person at one of our [https://moodle.com/events/ MoodleMoots]!&lt;br /&gt;
&lt;br /&gt;
Moodle also has an extensive network of [https://moodle.com/partners Moodle Partners]. Moodle Partners are service providers that are certified by Moodle HQ to provide high quality Moodle services for schools, institutions and organisations. We work closely with our partners to determine the needs of Moodle Users and improve the platform.&lt;br /&gt;
&lt;br /&gt;
Our Roadmap is built via our [http://docs.moodle.org/dev/Roadmap_process &amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Roadmap Process&amp;lt;/span&amp;gt;]. This process is continuously evolving but it always seeks to involve all our key stakeholders - students, teachers, admins, institutions, and of course our partners and supporters.&lt;br /&gt;
&lt;br /&gt;
= The big picture =&lt;br /&gt;
&lt;br /&gt;
Working on the Moodle learning platform involves millions of moving parts, and every release generally includes hundreds of improvements.  However, there are &#039;&#039;&#039;four main goals&#039;&#039;&#039; that we are focussing on for the next two years:&lt;br /&gt;
&lt;br /&gt;
=== User experience and flow ===&lt;br /&gt;
&lt;br /&gt;
The entire user experience from onboarding, into daily teaching/learning and expert customisation of Moodle is the core value of what makes Moodle useful or not in the real world, in fully online and blended modes.&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
While we’re working on hundreds of smaller, annoying issues, we are also doing some major re-thinking around what an LMS should be in the next decade and beyond as a tool to empower educators and learners.&lt;br /&gt;
&lt;br /&gt;
=== Enabling all our developers ===&lt;br /&gt;
&lt;br /&gt;
Our significant community of developers are an amazing group of over 1000 people - many of them make a living being part of the Moodle community.&lt;br /&gt;
&lt;br /&gt;
We are of course working on ways to make Moodle programming easier and better, with better training and support as well as improved APIs, plugins, integrations and support for modern technologies.&lt;br /&gt;
&lt;br /&gt;
However, a particularly exciting initiative is the new Moodle Plugins Service, due in 2021, which will provide an “app store” experience on which all developers can build financial sustainability for their work, while teachers will have easier access to use hundreds of new plugins in their courses via the web interface, without needing to convince their admins to install code. This will help the entire plugins ecosystem.&lt;br /&gt;
&lt;br /&gt;
===Better integrations between Moodle products===&lt;br /&gt;
&lt;br /&gt;
The current Moodle products already integrate with each other, of course, but there is much more to be done to make them work together more seamlessly, as part of one platform, so that our users have a better experience and also so that they become more aware of solutions to their problems.&lt;br /&gt;
&lt;br /&gt;
=== Better integration with the world ===&lt;br /&gt;
&lt;br /&gt;
Moodle is never used alone, and it is a part of many ecosystems at many levels. We must connect to all kinds of other systems, we must of course comply with new legislation such as the GDPR, Accessibility and much more.&lt;br /&gt;
&lt;br /&gt;
In particular though, we are committed to helping to promote [https://openedtech.global/ &amp;lt;span class=&amp;quot;underline&amp;quot;&amp;gt;Open EdTech&amp;lt;/span&amp;gt;] and to work closely with qualified Open EdTech products and major stakeholders to design and build an open architecture for a long-term future.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Roadmap timeline =&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! &#039;&#039;&#039;2020&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
LMS&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Cloud&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Net&#039;&#039;&#039;&lt;br /&gt;
! &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;Launch of new Moodle app plans&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Launch of Workplace hosting&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Free trials&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
LLTS&amp;lt;ref&amp;gt;Long Long Term Support&amp;lt;/ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Create H5P content&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
MoodleNet&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Activity chooser&lt;br /&gt;
&lt;br /&gt;
Participants filters (MUA)&lt;br /&gt;
&lt;br /&gt;
Accessibility&lt;br /&gt;
&lt;br /&gt;
Safe Exam Browser&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Appointments&lt;br /&gt;
&lt;br /&gt;
Data Importers and exporters&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Text editor draft autosave&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Updates:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle LMS 3.9 compatibility&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Moodle Workplace 3.9 compatibility&lt;br /&gt;
|&lt;br /&gt;
Improved connections with other Moodle products&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Self-service for renames and restores&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 1.0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Integrates to Moodle 3.9 and later&lt;br /&gt;
&lt;br /&gt;
Moderation&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Federation&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
HQ-run home instance&lt;br /&gt;
&lt;br /&gt;
GDPR compliance&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Themeable&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;MEC 2020 launch&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;6 courses covering all 22 competencies&lt;br /&gt;
&lt;br /&gt;
Translated into multiple languages&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Tenant-shared learning&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Notifications of new grades&lt;br /&gt;
&lt;br /&gt;
Improved connections with other products&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.1&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
New plans&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Updates:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Simplified signup and upgrades&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.2&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Report Builder improvements&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 3.9.2&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Functionality gaps for students&lt;br /&gt;
&lt;br /&gt;
UX improvements&lt;br /&gt;
| Improvements based on customer needs&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;MEC Direct Release&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;MEC licensing for large institutions&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2021&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
LMS&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Cloud&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Net&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;&#039;Release 3.9.3&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Dashboards&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Plugins Service Soft Launch&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| Other certifications&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;New:&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Workplace features:&amp;lt;br /&amp;gt;&lt;br /&gt;
- Certificates&amp;lt;br /&amp;gt;&lt;br /&gt;
- Report Builder&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
UX navigation&lt;br /&gt;
&lt;br /&gt;
UX biggest pains&lt;br /&gt;
&lt;br /&gt;
UX consistency via component library&lt;br /&gt;
&lt;br /&gt;
Information flow and task management&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
&#039;&#039;&#039;Release 4.0&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Improved:&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
Moodle LMS 4.0 compatibility&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Moodle Workplace 4.0 compatibility&lt;br /&gt;
&lt;br /&gt;
Classroom tools with friendly UX&lt;br /&gt;
| &#039;&#039;&#039;Release 4.0&amp;lt;br /&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;2022&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
LMS&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Workplace&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Apps&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Cloud&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle&amp;lt;br /&amp;gt;&lt;br /&gt;
Net&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Moodle Certificates&#039;&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.1&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q3&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;Q4&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
| &#039;&#039;&#039;Release 4.2&#039;&#039;&#039;&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Notes on some of these major release dates: ==&lt;br /&gt;
&lt;br /&gt;
===Moodle 4.0 in November 2021 ===&lt;br /&gt;
&lt;br /&gt;
Normally Moodle LMS major releases are every 6 months, in May and November.&lt;br /&gt;
&lt;br /&gt;
However, for our very large new releases such as 1.0, 2.0, 3.0 and now 4.0, we often take longer so that we can tackle more significant chunks of important core work, giving us the opportunity sometimes to make more serious changes to UX or architecture.&lt;br /&gt;
&lt;br /&gt;
There are a lot of ideas around for 4.0 - we will be relying on our new UX team to organise and prioritise a lot of it during the next 6 months.&lt;br /&gt;
&lt;br /&gt;
=== Moodle 3.9 release in June 2020 ===&lt;br /&gt;
&lt;br /&gt;
In support of a longer release timeframe for Moodle 4.0, we have decided to release Moodle 3.9 in June.&lt;br /&gt;
&lt;br /&gt;
The extra month will give us time to bring in a number of extra items in support of Moodle’s other products, which are in addition to the planned features for the 3.9 release.&lt;br /&gt;
&lt;br /&gt;
It will also allow us to include as many community contributions as possible as we work towards the release date.&lt;br /&gt;
&lt;br /&gt;
* Code freeze (no new features accepted): &#039;&#039;&#039;6th April 2020&#039;&#039;&#039;&lt;br /&gt;
* QA cycle (start of QA testing): &#039;&#039;&#039;13th April 2020&#039;&#039;&#039;&lt;br /&gt;
* Scheduled release date (once QA passed): &#039;&#039;&#039;11th May 2020&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=Past releases=&lt;br /&gt;
&lt;br /&gt;
See our [[Releases]] page for information about past releases.&lt;br /&gt;
&lt;br /&gt;
After Moodle 2.0 we switched to time-based releases rather than feature-based releases (see our [https://docs.moodle.org/dev/Process development process]). Because of this, the details above on future releases are an indication of current priorities only, and are targeted to be released in the upcoming releases. Anything not ready by the next release date will generally be pushed to the following major release.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Releases]] - versions of Moodle that have already been released&lt;br /&gt;
* https://docs.moodle.org/dev/Releases#General_release_calendar Key dates relating to future releases. &lt;br /&gt;
&lt;br /&gt;
[[es:Plan de desarrollo]] &lt;br /&gt;
[[fr:Planification]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Roadmap_process&amp;diff=56944</id>
		<title>Roadmap process</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Roadmap_process&amp;diff=56944"/>
		<updated>2020-02-23T15:08:13Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Created page with &amp;quot;== Roadmap Process == coming soon&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Roadmap Process ==&lt;br /&gt;
coming soon&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=55771</id>
		<title>Creating a theme based on boost</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=55771"/>
		<updated>2019-03-22T01:47:21Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.2}}&lt;br /&gt;
{{Template:Themes}}&lt;br /&gt;
&lt;br /&gt;
This is a tutorial for how to create a new theme in any version of Moodle from 3.2 and later.&lt;br /&gt;
&lt;br /&gt;
Moodle 3.2 introduced a new core theme named &amp;quot;Boost&amp;quot; which is a great starting point for themers wanting to build a modern Moodle theme utilising all the latest features available to themes in Moodle.  If you aren&#039;t sure where to start, then START HERE!  :-)&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 a working theme named &amp;quot;theme_photo&amp;quot; you can download it or view the source code for it here: https://github.com/damyon/moodle-theme_photo&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 moodle.org/plugins can save you a lot of work renaming things later.&lt;br /&gt;
&lt;br /&gt;
Lets call our new example theme &amp;quot;photo&amp;quot; as we will add some settings to allow &amp;quot;photos&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 we can start creating our 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/photo/&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/photo/version.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;
// This is the version of the plugin.                                                                                               &lt;br /&gt;
$plugin-&amp;gt;version = &#039;2016102100&#039;;                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
// This is the version of Moodle this plugin requires.                                                                              &lt;br /&gt;
$plugin-&amp;gt;requires = &#039;2016070700&#039;;                                                                                                   &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_photo&#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_boost&#039; =&amp;gt; &#039;2016102100&#039;                                                                                                   &lt;br /&gt;
];                                                                              &lt;br /&gt;
&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/photo/lang/en/theme_photo.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 photo is a child theme of Boost. 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;Photo&#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;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;
&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;
// $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;photo&#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 /style/ 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_boost because it provides a great starting point for SCSS bootstrap4   &lt;br /&gt;
// themes. We could 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;];                                                                                                        &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. Boost         &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 Boost based themes because Boost           &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;
// This is a list of blocks that are required to exist on all pages for this theme to function correctly. For example               &lt;br /&gt;
// bootstrap base requires the settings and navigation blocks because otherwise there would be no way to navigate to all the        &lt;br /&gt;
// pages in Moodle. Boost does not require these blocks because it provides other ways to navigate built into the theme.            &lt;br /&gt;
$THEME-&amp;gt;requiredblocks = &#039;&#039;;   &lt;br /&gt;
&lt;br /&gt;
// This is a feature that tells the blocks library not to use the &amp;quot;Add a block&amp;quot; block. We don&#039;t want this in boost based themes because&lt;br /&gt;
// it forces a block region into the page when editing is enabled and it takes up too much room.&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;
=== 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 Boost. 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. If you choose a different preset in Boost - it is not applied in this child theme.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warningbox&amp;quot;&amp;gt;&lt;br /&gt;
Note: make sure your config.php file contains $THEME-&amp;gt;hidefromselector = false; (or at least set to false) or else, your theme wont show up in theme selector.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What if I want the settings too? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warningbox&amp;quot;&amp;gt;&lt;br /&gt;
This section is included for completeness - but it is not recommended for themes to utilise settings from their parents. To find out how to duplicate the settings from the parent theme so they operate independently skip to [[#Duplicate the settings from Boost]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If I want the settings from Boost to apply to my child theme as well I need to know a bit about how each of the settings in Boost is applied to make them work in my child theme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Setting 1 - preset.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;preset&amp;quot; file is the file that is used as the main file for scss compilation. In Boost this is controlled by the theme config value:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&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;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_boost&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this function is doing is checking for a theme setting &amp;quot;preset&amp;quot; and either fetching the file from Moodles internal file storage, or from the /preset/ folder. The function then returns the contents of this file.&lt;br /&gt;
&lt;br /&gt;
It does not automatically work for our child theme because we have no setting named &amp;quot;preset&amp;quot; in our child theme and this code is not searching the theme parents for the setting. If we wanted it to apply we could do this in our child theme:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This setting defines the main scss file for our theme to be compiled. We could set it to a static file in the scss folder or to a function which returns the SCSS based on theme settings.&lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
&lt;br /&gt;
    // We need to load the config for our parent theme because that is where the preset setting is defined.&lt;br /&gt;
    $parentconfig = theme_config::load(&#039;boost&#039;);&lt;br /&gt;
    // Call a function from our parent themes lib.php file to fetch the content of the themes main SCSS file based on it&#039;s own config, not ours.&lt;br /&gt;
    return theme_boost_get_main_scss_content($parentconfig);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Settings 2+3 brandcolor + scsspre&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The way these settings work is they generate a chunk of SCSS to be prepended to the main scss file. In boost they work like this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_boost_get_pre_scss&#039;; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_pre_scss($theme) {                                                                                         &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $configurable = [                                                                                                               &lt;br /&gt;
        // Config key =&amp;gt; [variableName, ...].                                                                                       &lt;br /&gt;
        &#039;brandcolor&#039; =&amp;gt; [&#039;brand-primary&#039;],                                                                                          &lt;br /&gt;
    ];                                                                                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Prepend variables first.                                                                                                     &lt;br /&gt;
    foreach ($configurable as $configkey =&amp;gt; $targets) {                                                                             &lt;br /&gt;
        $value = isset($theme-&amp;gt;settings-&amp;gt;{$configkey}) ? $theme-&amp;gt;settings-&amp;gt;{$configkey} : null;                                     &lt;br /&gt;
        if (empty($value)) {                                                                                                        &lt;br /&gt;
            continue;                                                                                                               &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        array_map(function($target) use (&amp;amp;$scss, $value) {                                                                          &lt;br /&gt;
            $scss .= &#039;$&#039; . $target . &#039;: &#039; . $value . &amp;quot;;\n&amp;quot;;                                                                         &lt;br /&gt;
        }, (array) $targets);                                                                                                       &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Prepend pre-scss.                                                                                                            &lt;br /&gt;
    if (!empty($theme-&amp;gt;settings-&amp;gt;scsspre)) {                                                                                        &lt;br /&gt;
        $scss .= $theme-&amp;gt;settings-&amp;gt;scsspre;                                                                                         &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this code is doing is: &lt;br /&gt;
* looping over a list of theme settings that map to a SCSS variable and building some SCSS to initialise that variable from the setting. In Boost there is only one * brandprimary - but if we wanted to expose more bootstrap variables as theme settings we could use this function as a template in our child theme and add more settings to the $configurable array.&lt;br /&gt;
* Adding all of the raw SCSS from the scsspre theme setting&lt;br /&gt;
* Returning the whole thing as a string to be added before the main scss file.&lt;br /&gt;
&lt;br /&gt;
If we want this code to work in our child theme, using the settings from Boost we could do this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This is a function that returns some SCSS as a string to prepend to the main SCSS file.                                          &lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_photo_get_pre_scss&#039;;               &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Function to return the SCSS to prepend to our main SCSS for this theme.&lt;br /&gt;
// Note the function name starts with the component name because this is a global function and we don&#039;t want namespace clashes.&lt;br /&gt;
function theme_photo_get_pre_scss($theme) {&lt;br /&gt;
    // Load the settings from the parent.                                                                                           &lt;br /&gt;
    $theme = theme_config::load(&#039;boost&#039;);                                                                                           &lt;br /&gt;
    // Call the parent themes get_pre_scss function.                                                                                &lt;br /&gt;
    return theme_boost_get_pre_scss($theme);                         &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Setting 4 scss (post)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The final setting from Boost is a raw text field which adds SCSS to the end of the main SCSS file. This is a useful place to add style rules as they will override previously defined styles with the same specificity. It is applied in Boost by the following lines:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_boost_get_extra_scss&#039;; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_extra_scss($theme) {                                                                                       &lt;br /&gt;
    return !empty($theme-&amp;gt;settings-&amp;gt;scss) ? $theme-&amp;gt;settings-&amp;gt;scss : &#039;&#039;;                                                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is just returning the value of the setting as a string.&lt;br /&gt;
&lt;br /&gt;
To make this setting apply in our child theme too - we use similar code to the previous sections.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This is a function that returns some SCSS as a string to prepend to the main SCSS file.                                          &lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_photo_get_extra_scss&#039;;               &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Function to return the SCSS to append to our main SCSS for this theme.&lt;br /&gt;
// Note the function name starts with the component name because this is a global function and we don&#039;t want namespace clashes.&lt;br /&gt;
function theme_photo_get_extra_scss($theme) {&lt;br /&gt;
    // Load the settings from the parent.                                                                                           &lt;br /&gt;
    $theme = theme_config::load(&#039;boost&#039;);                                                                                           &lt;br /&gt;
    // Call the parent themes get_extra_scss function.                                                                                &lt;br /&gt;
    return theme_boost_get_extra_scss($theme);                         &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Duplicate the settings from Boost  ===&lt;br /&gt;
&lt;br /&gt;
This is the recommended way to extend boost as your child theme will not be affected by changes to the Boost settings, and both themes can be in use with different settings applied.&lt;br /&gt;
&lt;br /&gt;
All that needs to happen is to create theme settings in the child theme that match each of the settings in the parent theme. You will need to add matching language strings for each of these settings in the language file.&lt;br /&gt;
&lt;br /&gt;
This example shows how to do it - We are re-using the nice looking theme_boost_admin_settingspage_tabs class from boost and creating duplicate versions of each of the settings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&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;
// This is used for performance, we don&#039;t need to know about these settings on every page in Moodle, only when                      &lt;br /&gt;
// we are looking at the admin settings pages.                                                                                      &lt;br /&gt;
if ($ADMIN-&amp;gt;fulltree) {                                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Boost provides a nice setting page which splits settings onto separate tabs. We want to use it here.                         &lt;br /&gt;
    $settings = new theme_boost_admin_settingspage_tabs(&#039;themesettingphoto&#039;, get_string(&#039;configtitle&#039;, &#039;theme_photo&#039;));             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Each page is a tab - the first is the &amp;quot;General&amp;quot; tab.                                                                         &lt;br /&gt;
    $page = new admin_settingpage(&#039;theme_photo_general&#039;, get_string(&#039;generalsettings&#039;, &#039;theme_photo&#039;));                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Replicate the preset setting from boost.                                                                                     &lt;br /&gt;
    $name = &#039;theme_photo/preset&#039;;                                                                                                   &lt;br /&gt;
    $title = get_string(&#039;preset&#039;, &#039;theme_photo&#039;);                                                                                   &lt;br /&gt;
    $description = get_string(&#039;preset_desc&#039;, &#039;theme_photo&#039;);                                                                        &lt;br /&gt;
    $default = &#039;default.scss&#039;;                                                                                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // We list files in our own file area to add to the drop down. We will provide our own function to                              &lt;br /&gt;
    // load all the presets from the correct paths.                                                                                 &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    $files = $fs-&amp;gt;get_area_files($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;itemid, filepath, filename&#039;, false);                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $choices = [];                                                                                                                  &lt;br /&gt;
    foreach ($files as $file) {                                                                                                     &lt;br /&gt;
        $choices[$file-&amp;gt;get_filename()] = $file-&amp;gt;get_filename();                                                                    &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
    // These are the built in presets from Boost.                                                                                   &lt;br /&gt;
    $choices[&#039;default.scss&#039;] = &#039;default.scss&#039;;                                                                                      &lt;br /&gt;
    $choices[&#039;plain.scss&#039;] = &#039;plain.scss&#039;;                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $setting = new admin_setting_configselect($name, $title, $description, $default, $choices);                                     &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Preset files setting.                                                                                                        &lt;br /&gt;
    $name = &#039;theme_photo/presetfiles&#039;;                                                                                              &lt;br /&gt;
    $title = get_string(&#039;presetfiles&#039;,&#039;theme_photo&#039;);                                                                               &lt;br /&gt;
    $description = get_string(&#039;presetfiles_desc&#039;, &#039;theme_photo&#039;);                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;preset&#039;, 0,                                         &lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; 20, &#039;accepted_types&#039; =&amp;gt; array(&#039;.scss&#039;)));                                                               &lt;br /&gt;
    $page-&amp;gt;add($setting);     &lt;br /&gt;
&lt;br /&gt;
    // Variable $brand-color.                                                                                                       &lt;br /&gt;
    // We use an empty default value because the default colour should come from the preset.                                        &lt;br /&gt;
    $name = &#039;theme_photo/brandcolor&#039;;                                                                                               &lt;br /&gt;
    $title = get_string(&#039;brandcolor&#039;, &#039;theme_photo&#039;);                                                                               &lt;br /&gt;
    $description = get_string(&#039;brandcolor_desc&#039;, &#039;theme_photo&#039;);                                                                    &lt;br /&gt;
    $setting = new admin_setting_configcolourpicker($name, $title, $description, &#039;&#039;);                                               &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Must add the page after definiting all the settings!                                                                         &lt;br /&gt;
    $settings-&amp;gt;add($page);                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Advanced settings.                                                                                                           &lt;br /&gt;
    $page = new admin_settingpage(&#039;theme_photo_advanced&#039;, get_string(&#039;advancedsettings&#039;, &#039;theme_photo&#039;));                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Raw SCSS to include before the content.                                                                                      &lt;br /&gt;
    $setting = new admin_setting_configtextarea(&#039;theme_photo/scsspre&#039;,                                                              &lt;br /&gt;
        get_string(&#039;rawscsspre&#039;, &#039;theme_photo&#039;), get_string(&#039;rawscsspre_desc&#039;, &#039;theme_photo&#039;), &#039;&#039;, PARAM_RAW);                      &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Raw SCSS to include after the content.                                                                                       &lt;br /&gt;
    $setting = new admin_setting_configtextarea(&#039;theme_photo/scss&#039;, get_string(&#039;rawscss&#039;, &#039;theme_photo&#039;),                           &lt;br /&gt;
        get_string(&#039;rawscss_desc&#039;, &#039;theme_photo&#039;), &#039;&#039;, PARAM_RAW);                                                                  &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $settings-&amp;gt;add($page);                                                                                                          &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lang/en/theme_photo.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;
// The name of the second tab in the theme settings.                                                                                &lt;br /&gt;
$string[&#039;advancedsettings&#039;] = &#039;Advanced settings&#039;;                                                                                  &lt;br /&gt;
// The brand colour setting.                                                                                                        &lt;br /&gt;
$string[&#039;brandcolor&#039;] = &#039;Brand colour&#039;;                                                                                             &lt;br /&gt;
// The brand colour setting description.                                                                                            &lt;br /&gt;
$string[&#039;brandcolor_desc&#039;] = &#039;The accent colour.&#039;;     &lt;br /&gt;
// A description shown in the admin theme selector.                                                                                 &lt;br /&gt;
$string[&#039;choosereadme&#039;] = &#039;Theme photo is a child theme of Boost. It adds the ability to upload background photos.&#039;;                &lt;br /&gt;
// Name of the settings pages.                                                                                                      &lt;br /&gt;
$string[&#039;configtitle&#039;] = &#039;Photo settings&#039;;                                                                                          &lt;br /&gt;
// Name of the first settings tab.                                                                                                  &lt;br /&gt;
$string[&#039;generalsettings&#039;] = &#039;General settings&#039;;                                                                                    &lt;br /&gt;
// The name of our plugin.                                                                                                          &lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Photo&#039;;                                                                                                    &lt;br /&gt;
// Preset files setting.                                                                                                            &lt;br /&gt;
$string[&#039;presetfiles&#039;] = &#039;Additional theme preset files&#039;;                                                                           &lt;br /&gt;
// Preset files help text.                                                                                                          &lt;br /&gt;
$string[&#039;presetfiles_desc&#039;] = &#039;Preset files can be used to dramatically alter the appearance of the theme. See &amp;lt;a href=https://docs.moodle.org/dev/Boost_Presets&amp;gt;Boost presets&amp;lt;/a&amp;gt; for information on creating and sharing your own preset files, and see the &amp;lt;a href=http://moodle.net/boost&amp;gt;Presets repository&amp;lt;/a&amp;gt; for presets that others have shared.&#039;;&lt;br /&gt;
// Preset setting.                                                                                                                  &lt;br /&gt;
$string[&#039;preset&#039;] = &#039;Theme preset&#039;;                                                                                                 &lt;br /&gt;
// Preset help text.                                                                                                                &lt;br /&gt;
$string[&#039;preset_desc&#039;] = &#039;Pick a preset to broadly change the look of the theme.&#039;;                                                  &lt;br /&gt;
// Raw SCSS setting.                                                                                                                &lt;br /&gt;
$string[&#039;rawscss&#039;] = &#039;Raw SCSS&#039;;                                                                                                    &lt;br /&gt;
// Raw SCSS setting help text.                                                                                                      &lt;br /&gt;
$string[&#039;rawscss_desc&#039;] = &#039;Use this field to provide SCSS or CSS code which will be injected at the end of the style sheet.&#039;;       &lt;br /&gt;
// Raw initial SCSS setting.                                                                                                        &lt;br /&gt;
$string[&#039;rawscsspre&#039;] = &#039;Raw initial SCSS&#039;;                                                                                         &lt;br /&gt;
// Raw initial SCSS setting help text.                                                                                              &lt;br /&gt;
$string[&#039;rawscsspre_desc&#039;] = &#039;In this field you can provide initialising SCSS code, it will be injected before everything else. Most of the time you will use this setting to define variables.&#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;Right&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We aren&#039;t quite there yet as you will notice if you try and upload a preset file and then choose it. The &amp;quot;theme_boost_get_main_scss_content&amp;quot; function from Boost is expecting the preset files to be stored in a file area for theme_boost only. We need to add this function to our own theme and tweak it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;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. We override the boost version because          &lt;br /&gt;
// we want to allow presets uploaded to our own theme file area to be selected in the preset list.                                  &lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {                                                                                                   &lt;br /&gt;
    return theme_photo_get_main_scss_content($theme);                                                                               &lt;br /&gt;
}; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        // This preset file was fetched from the file area for theme_photo and not theme_boost (see the line above).                &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}             &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Stop and try it out ===&lt;br /&gt;
So now what is working and what isn&#039;t. Well - everything should be working and you should have a nice new theme extending boost with it&#039;s own settings pages. When Boost gets updates for bug fixes your new theme will inherit those fixes as it inherits all the SCSS and templates from theme boost. In addition your new theme will accept preset files and supports all the same features and settings as boost, ready to add more.&lt;br /&gt;
&lt;br /&gt;
== Take it further ==&lt;br /&gt;
Now we have our very nice starting point we can start changing or adding features, customising templates and output or tweaking the SCSS.&lt;br /&gt;
&lt;br /&gt;
=== Add some new settings ===&lt;br /&gt;
&lt;br /&gt;
From this point in the tutorial we will start adding features to our theme to extend it and make it AWESOME!&lt;br /&gt;
&lt;br /&gt;
Lets start with a new setting to set a background image on the login page. As you saw earlier, our theme defines it&#039;s list of settings in a file called settings.php. See [[Admin settings]] for more information about adding admin settings to any plugin. All of the different kinds of admin settings can be found in lib/adminlib.php. In our case we will want to add a setting which allows an admin to upload an image file. This is an &amp;quot;admin_setting_configstoredfile&amp;quot; and we add it to our theme by adding  this code to the settings.php file (inside the &amp;quot;if ($ADMIN-&amp;gt;fulltree) {&amp;quot; condition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    // Login page background setting.                                                                                               &lt;br /&gt;
    // We use variables for readability.                                                                                            &lt;br /&gt;
    $name = &#039;theme_photo/loginbackgroundimage&#039;;                                                                                     &lt;br /&gt;
    $title = get_string(&#039;loginbackgroundimage&#039;, &#039;theme_photo&#039;);                                                                     &lt;br /&gt;
    $description = get_string(&#039;loginbackgroundimage_desc&#039;, &#039;theme_photo&#039;);                                                          &lt;br /&gt;
    // This creates the new setting.                                                                                                &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;loginbackgroundimage&#039;);                             &lt;br /&gt;
    // This means that theme caches will automatically be cleared when this setting is changed.                                     &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    // We always have to add the setting to a page for it to have any effect.                                                       &lt;br /&gt;
    $page-&amp;gt;add($setting);       &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to add new lang strings to our language file.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lang/en/theme_photo.php&amp;quot;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Background image for login page.                                                                                                 &lt;br /&gt;
$string[&#039;loginbackgroundimage&#039;] = &#039;Login page background image&#039;;                                                                    &lt;br /&gt;
// Background image for login page.                                                                                                 &lt;br /&gt;
$string[&#039;loginbackgroundimage_desc&#039;] = &#039;An image that will be stretched to fill the background of the login page.&#039;;                 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we have a new setting that lets us upload a file - but it doesn&#039;t actually do anything yet. We need to update the theme to set this image background on the login page.&lt;br /&gt;
&lt;br /&gt;
In order to change the SCSS for our theme we will add 2 additional SCSS files and include them before and after our main scss.&lt;br /&gt;
&lt;br /&gt;
We already have a function in our lib.php file which fetches the main SCSS for our theme. This is a good point to include additional SCSS files. We can add 2 lines to the end of this function to achieve this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        // This preset file was fetched from the file area for theme_photo and not theme_boost (see the line above).                &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                               &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/photo/scss/pre.scss&#039;);                                                         &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/photo/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;
&#039;&#039;scss/pre.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// Pre SCSS for the theme.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;scss/post.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// Post SCSS for the theme.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why do we use pre and post SCSS? ====&lt;br /&gt;
SCSS/SASS is a powerful language for creating CSS. It supports variables, functions, loops just like php. For lots of information and an introduction to SCSS read about [https://en.wikipedia.org/wiki/Sass_(stylesheet_language) Sass on wikipedia]. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pre SCSS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In Boost we use many variables when creating style rules.&lt;br /&gt;
&lt;br /&gt;
When declaring a variable in SCSS - it is best practice to define it like this:&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
$mycoolcolour: #FF0 !default;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this means is - if this variable is not defined already - set it to the hex value &#039;#FF0&#039;;&lt;br /&gt;
&lt;br /&gt;
So by setting this variable in some PRE scss we can override the default the value of this variable everywhere it is used. Boost is built with the [https://v4-alpha.getbootstrap.com/ Bootstrap 4 (Alpha 4)] CSS Framework. This is a framework which uses SCSS to provide many extremely useful layouts and components which can be reused without adding specific CSS rules to style every page. Because bootstrap consistently uses variables we can customise many of these components easily by setting the value of the variables before we include the Bootstrap SCSS files.&lt;br /&gt;
&lt;br /&gt;
Many variables are available in /theme/boost/scss/bootstrap/_variables.scss - as an example we can change the look of all buttons and input fields with this one variable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
$border-radius: 8px;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Post SCSS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Post SCSS is useful for defining full CSS rules. Because they are included last, they override any previous matching selector with the same [https://en.wikipedia.org/wiki/Cascading_Style_Sheets#Specificity Specificity].&lt;br /&gt;
&lt;br /&gt;
=== Tips for customising Moodle with SCSS (or CSS) ===&lt;br /&gt;
Some handy things to know when you are new to theming is that Moodle adds some classes to every page that helps you target a specific page or set of pages with some style rules. &lt;br /&gt;
&lt;br /&gt;
If you inspect a moodle page and look at the body tag you will see a long list of classes e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
&amp;lt;body id=&amp;quot;page-course-view-weeks&amp;quot; class=&amp;quot;format-weeks  path-course path-course-view safari dir-ltr lang-en yui-skin-sam yui3-skin-sam damyon-per-in-moodle-com--stable_master pagelayout-course course-11 context-497 category-1 drawer-open-left jsenabled&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see from this example that each page gets an id. This is a simplified representation of the current page in the navigation. In this example we are looking at the course page and this course is using the weeks format. &lt;br /&gt;
&lt;br /&gt;
The classes on the body tag can also be used to target a page or set of pages.&lt;br /&gt;
* &amp;lt;code&amp;gt;format-weeks&amp;lt;/code&amp;gt; The course format&lt;br /&gt;
* &amp;lt;code&amp;gt;path-course path-course-view&amp;lt;/code&amp;gt; The parts of the bread-crumb leading up to the current page (The current page is what goes in the id)&lt;br /&gt;
* &amp;lt;code&amp;gt;safari&amp;lt;/code&amp;gt; Some server side guessing of the browser type - it&#039;s not accurate so I would not rely on it&lt;br /&gt;
* &amp;lt;code&amp;gt;dir-ltr&amp;lt;/code&amp;gt; The direction of the current language for the page ( dir-rtl for RTL languages )&lt;br /&gt;
* &amp;lt;code&amp;gt;lang-en&amp;lt;/code&amp;gt; The current language of the page&lt;br /&gt;
* &amp;lt;code&amp;gt;yui*&amp;lt;/code&amp;gt; Legacy yui classes - ignore these&lt;br /&gt;
* &amp;lt;code&amp;gt;damyon-per-in-moodle-com--stable_master&amp;lt;/code&amp;gt; The current hostname for the site + the site name&lt;br /&gt;
* &amp;lt;code&amp;gt;pagelayout-course&amp;lt;/code&amp;gt; The layout type for the current page&lt;br /&gt;
* &amp;lt;code&amp;gt;course-11&amp;lt;/code&amp;gt; The id of the current course&lt;br /&gt;
* &amp;lt;code&amp;gt;context-497&amp;lt;/code&amp;gt; The current context id&lt;br /&gt;
* &amp;lt;code&amp;gt;category-1&amp;lt;/code&amp;gt; The category for the current course&lt;br /&gt;
* &amp;lt;code&amp;gt;drawer-open-left&amp;lt;/code&amp;gt; Added / removed when the navigation drawer is opened / closed in Boost&lt;br /&gt;
* &amp;lt;code&amp;gt;jsenabled&amp;lt;/code&amp;gt; True if the browser supports javascript&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Themes_overview#.3Cbody.3E_CSS_id_and_classes Read about Body id and classes].&lt;br /&gt;
&lt;br /&gt;
In our example the page layout is the most useful here as we have a specific page layout for login pages. We can now craft a rule that applies a background image only to login pages using &amp;quot;body.pagelayout-login&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== How do we refer to an image in SCSS ? ===&lt;br /&gt;
So now we can add a rule to the post.scss which will set the background image for the login page. First we need to know how to construct a url to the background images from our stylesheet. &lt;br /&gt;
&lt;br /&gt;
In stylesheets in Moodle we can use a special pix tag to refer to images from our theme. The rule to attach the background image looks like this:&lt;br /&gt;
&#039;&#039;scss/post.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
body.pagelayout-login {                                                                                                             &lt;br /&gt;
    background-image: url([[pix:theme_photo|loginbackgroundimage]]);                                                                &lt;br /&gt;
    background-size: cover;                                                                                                         &lt;br /&gt;
}                          &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are 2 important parts to this tag (the bit in square brackets). The first is &amp;quot;theme_photo&amp;quot;. In this case we are passing a component name, the image serving code in theme_config::resolve_image_location() will then look for an image file in several locations. One of these is in &amp;quot;$CFG-&amp;gt;dataroot/pix_plugins/$type/$plugin/$image&amp;quot;. We can use this to make sure the image gets served correctly by copying the file saved in the setting to this location every time it is updated. (There is an alterative way we could do this by implementing pluginfile.php in our theme - which you can read about in the [[File API]] ).&lt;br /&gt;
&lt;br /&gt;
If we had just passed the value &amp;quot;theme&amp;quot; the image serving code would have looked for the image in the &amp;quot;pix&amp;quot; folder of our theme.&lt;br /&gt;
&lt;br /&gt;
So - we need this final change to copy the image file into our dataroot each time the setting is changed.&lt;br /&gt;
&lt;br /&gt;
In the settings file we will update the callback to a new function which we will define in our lib.php.&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    // Login page background setting.                                                                                               &lt;br /&gt;
    // We use variables for readability.                                                                                            &lt;br /&gt;
    $name = &#039;theme_photo/loginbackgroundimage&#039;;                                                                                     &lt;br /&gt;
    $title = get_string(&#039;loginbackgroundimage&#039;, &#039;theme_photo&#039;);                                                                     &lt;br /&gt;
    $description = get_string(&#039;loginbackgroundimage_desc&#039;, &#039;theme_photo&#039;);                                                          &lt;br /&gt;
    // This creates the new setting.                                                                                                &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;loginbackgroundimage&#039;);                             &lt;br /&gt;
    // This function will copy the image into the data_root location it can be served from.                                         &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_photo_update_settings_images&#039;);                                                            &lt;br /&gt;
    // We always have to add the setting to a page for it to have any effect.                                                       &lt;br /&gt;
    $page-&amp;gt;add($setting);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_update_settings_images($settingname) {                                                                         &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // The setting name that was updated comes as a string like &#039;s_theme_photo_loginbackgroundimage&#039;.                               &lt;br /&gt;
    // We split it on &#039;_&#039; characters.                                                                                               &lt;br /&gt;
    $parts = explode(&#039;_&#039;, $settingname);                                                                                            &lt;br /&gt;
    // And get the last one to get the setting name..                                                                               &lt;br /&gt;
    $settingname = end($parts);                                                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Admin settings are stored in system context.                                                                                 &lt;br /&gt;
    $syscontext = context_system::instance();                                                                                       &lt;br /&gt;
    // This is the component name the setting is stored in.                                                                         &lt;br /&gt;
    $component = &#039;theme_photo&#039;;                                                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // This is the value of the admin setting which is the filename of the uploaded file.                                           &lt;br /&gt;
    $filename = get_config($component, $settingname);                                                                               &lt;br /&gt;
    // We extract the file extension because we want to preserve it.                                                                &lt;br /&gt;
    $extension = substr($filename, strrpos($filename, &#039;.&#039;) + 1);                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // This is the path in the moodle internal file system.                                                                         &lt;br /&gt;
    $fullpath = &amp;quot;/{$syscontext-&amp;gt;id}/{$component}/{$settingname}/0{$filename}&amp;quot;;                                                      &lt;br /&gt;
    // Get an instance of the moodle file storage.                                                                                  &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    // This is an efficient way to get a file if we know the exact path.                                                            &lt;br /&gt;
    if ($file = $fs-&amp;gt;get_file_by_hash(sha1($fullpath))) {                                                                           &lt;br /&gt;
        // We got the stored file - copy it to dataroot.                                                                            &lt;br /&gt;
        // This location matches the searched for location in theme_config::resolve_image_location.                                 &lt;br /&gt;
        $pathname = $CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039; . $settingname . &#039;.&#039; . $extension;                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // This pattern matches any previous files with maybe different file extensions.                                            &lt;br /&gt;
        $pathpattern = $CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039; . $settingname . &#039;.*&#039;;                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Make sure this dir exists.                                                                                               &lt;br /&gt;
        @mkdir($CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039;, $CFG-&amp;gt;directorypermissions, true);                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Delete any existing files for this setting.                                                                              &lt;br /&gt;
        foreach (glob($pathpattern) as $filename) {                                                                                 &lt;br /&gt;
            @unlink($filename);                                                                                                     &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Copy the current file to this location.                                                                                  &lt;br /&gt;
        $file-&amp;gt;copy_content_to($pathname);                                                                                          &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Reset theme caches.                                                                                                          &lt;br /&gt;
    theme_reset_all_caches();                                                                                                       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I won&#039;t show it here - but it is now easy to add a new background image setting for every layout type. I can re-use this theme_photo_update_settings_images callback for each one - so all I have to do is add the setting to the settings.php file, add the SCSS rule to the scss/post.scss file and add the lang strings to the language file.&lt;br /&gt;
&lt;br /&gt;
Thats 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>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=55770</id>
		<title>Creating a theme based on boost</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=55770"/>
		<updated>2019-03-22T01:47:02Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.2}}&lt;br /&gt;
{{Template:Themes}}&lt;br /&gt;
&lt;br /&gt;
This is a tutorial for how to create a new theme in any version of Moodle from 3.2 and later.&lt;br /&gt;
&lt;br /&gt;
Moodle 3.2 includes a new core theme named &amp;quot;Boost&amp;quot; which is a great starting point for themers wanting to build a modern Moodle theme utilising all the latest features available to themes in Moodle.  If you aren&#039;t sure where to start, then START HERE!  :-)&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 a working theme named &amp;quot;theme_photo&amp;quot; you can download it or view the source code for it here: https://github.com/damyon/moodle-theme_photo&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 moodle.org/plugins can save you a lot of work renaming things later.&lt;br /&gt;
&lt;br /&gt;
Lets call our new example theme &amp;quot;photo&amp;quot; as we will add some settings to allow &amp;quot;photos&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 we can start creating our 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/photo/&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/photo/version.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;
// This is the version of the plugin.                                                                                               &lt;br /&gt;
$plugin-&amp;gt;version = &#039;2016102100&#039;;                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
// This is the version of Moodle this plugin requires.                                                                              &lt;br /&gt;
$plugin-&amp;gt;requires = &#039;2016070700&#039;;                                                                                                   &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_photo&#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_boost&#039; =&amp;gt; &#039;2016102100&#039;                                                                                                   &lt;br /&gt;
];                                                                              &lt;br /&gt;
&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/photo/lang/en/theme_photo.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 photo is a child theme of Boost. 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;Photo&#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;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;
&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;
// $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;photo&#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 /style/ 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_boost because it provides a great starting point for SCSS bootstrap4   &lt;br /&gt;
// themes. We could 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;];                                                                                                        &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. Boost         &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 Boost based themes because Boost           &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;
// This is a list of blocks that are required to exist on all pages for this theme to function correctly. For example               &lt;br /&gt;
// bootstrap base requires the settings and navigation blocks because otherwise there would be no way to navigate to all the        &lt;br /&gt;
// pages in Moodle. Boost does not require these blocks because it provides other ways to navigate built into the theme.            &lt;br /&gt;
$THEME-&amp;gt;requiredblocks = &#039;&#039;;   &lt;br /&gt;
&lt;br /&gt;
// This is a feature that tells the blocks library not to use the &amp;quot;Add a block&amp;quot; block. We don&#039;t want this in boost based themes because&lt;br /&gt;
// it forces a block region into the page when editing is enabled and it takes up too much room.&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;
=== 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 Boost. 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. If you choose a different preset in Boost - it is not applied in this child theme.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warningbox&amp;quot;&amp;gt;&lt;br /&gt;
Note: make sure your config.php file contains $THEME-&amp;gt;hidefromselector = false; (or at least set to false) or else, your theme wont show up in theme selector.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What if I want the settings too? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warningbox&amp;quot;&amp;gt;&lt;br /&gt;
This section is included for completeness - but it is not recommended for themes to utilise settings from their parents. To find out how to duplicate the settings from the parent theme so they operate independently skip to [[#Duplicate the settings from Boost]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If I want the settings from Boost to apply to my child theme as well I need to know a bit about how each of the settings in Boost is applied to make them work in my child theme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Setting 1 - preset.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;preset&amp;quot; file is the file that is used as the main file for scss compilation. In Boost this is controlled by the theme config value:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&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;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_boost&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this function is doing is checking for a theme setting &amp;quot;preset&amp;quot; and either fetching the file from Moodles internal file storage, or from the /preset/ folder. The function then returns the contents of this file.&lt;br /&gt;
&lt;br /&gt;
It does not automatically work for our child theme because we have no setting named &amp;quot;preset&amp;quot; in our child theme and this code is not searching the theme parents for the setting. If we wanted it to apply we could do this in our child theme:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This setting defines the main scss file for our theme to be compiled. We could set it to a static file in the scss folder or to a function which returns the SCSS based on theme settings.&lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
&lt;br /&gt;
    // We need to load the config for our parent theme because that is where the preset setting is defined.&lt;br /&gt;
    $parentconfig = theme_config::load(&#039;boost&#039;);&lt;br /&gt;
    // Call a function from our parent themes lib.php file to fetch the content of the themes main SCSS file based on it&#039;s own config, not ours.&lt;br /&gt;
    return theme_boost_get_main_scss_content($parentconfig);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Settings 2+3 brandcolor + scsspre&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The way these settings work is they generate a chunk of SCSS to be prepended to the main scss file. In boost they work like this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_boost_get_pre_scss&#039;; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_pre_scss($theme) {                                                                                         &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $configurable = [                                                                                                               &lt;br /&gt;
        // Config key =&amp;gt; [variableName, ...].                                                                                       &lt;br /&gt;
        &#039;brandcolor&#039; =&amp;gt; [&#039;brand-primary&#039;],                                                                                          &lt;br /&gt;
    ];                                                                                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Prepend variables first.                                                                                                     &lt;br /&gt;
    foreach ($configurable as $configkey =&amp;gt; $targets) {                                                                             &lt;br /&gt;
        $value = isset($theme-&amp;gt;settings-&amp;gt;{$configkey}) ? $theme-&amp;gt;settings-&amp;gt;{$configkey} : null;                                     &lt;br /&gt;
        if (empty($value)) {                                                                                                        &lt;br /&gt;
            continue;                                                                                                               &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        array_map(function($target) use (&amp;amp;$scss, $value) {                                                                          &lt;br /&gt;
            $scss .= &#039;$&#039; . $target . &#039;: &#039; . $value . &amp;quot;;\n&amp;quot;;                                                                         &lt;br /&gt;
        }, (array) $targets);                                                                                                       &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Prepend pre-scss.                                                                                                            &lt;br /&gt;
    if (!empty($theme-&amp;gt;settings-&amp;gt;scsspre)) {                                                                                        &lt;br /&gt;
        $scss .= $theme-&amp;gt;settings-&amp;gt;scsspre;                                                                                         &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this code is doing is: &lt;br /&gt;
* looping over a list of theme settings that map to a SCSS variable and building some SCSS to initialise that variable from the setting. In Boost there is only one * brandprimary - but if we wanted to expose more bootstrap variables as theme settings we could use this function as a template in our child theme and add more settings to the $configurable array.&lt;br /&gt;
* Adding all of the raw SCSS from the scsspre theme setting&lt;br /&gt;
* Returning the whole thing as a string to be added before the main scss file.&lt;br /&gt;
&lt;br /&gt;
If we want this code to work in our child theme, using the settings from Boost we could do this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This is a function that returns some SCSS as a string to prepend to the main SCSS file.                                          &lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_photo_get_pre_scss&#039;;               &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Function to return the SCSS to prepend to our main SCSS for this theme.&lt;br /&gt;
// Note the function name starts with the component name because this is a global function and we don&#039;t want namespace clashes.&lt;br /&gt;
function theme_photo_get_pre_scss($theme) {&lt;br /&gt;
    // Load the settings from the parent.                                                                                           &lt;br /&gt;
    $theme = theme_config::load(&#039;boost&#039;);                                                                                           &lt;br /&gt;
    // Call the parent themes get_pre_scss function.                                                                                &lt;br /&gt;
    return theme_boost_get_pre_scss($theme);                         &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Setting 4 scss (post)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The final setting from Boost is a raw text field which adds SCSS to the end of the main SCSS file. This is a useful place to add style rules as they will override previously defined styles with the same specificity. It is applied in Boost by the following lines:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_boost_get_extra_scss&#039;; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_extra_scss($theme) {                                                                                       &lt;br /&gt;
    return !empty($theme-&amp;gt;settings-&amp;gt;scss) ? $theme-&amp;gt;settings-&amp;gt;scss : &#039;&#039;;                                                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is just returning the value of the setting as a string.&lt;br /&gt;
&lt;br /&gt;
To make this setting apply in our child theme too - we use similar code to the previous sections.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This is a function that returns some SCSS as a string to prepend to the main SCSS file.                                          &lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_photo_get_extra_scss&#039;;               &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Function to return the SCSS to append to our main SCSS for this theme.&lt;br /&gt;
// Note the function name starts with the component name because this is a global function and we don&#039;t want namespace clashes.&lt;br /&gt;
function theme_photo_get_extra_scss($theme) {&lt;br /&gt;
    // Load the settings from the parent.                                                                                           &lt;br /&gt;
    $theme = theme_config::load(&#039;boost&#039;);                                                                                           &lt;br /&gt;
    // Call the parent themes get_extra_scss function.                                                                                &lt;br /&gt;
    return theme_boost_get_extra_scss($theme);                         &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Duplicate the settings from Boost  ===&lt;br /&gt;
&lt;br /&gt;
This is the recommended way to extend boost as your child theme will not be affected by changes to the Boost settings, and both themes can be in use with different settings applied.&lt;br /&gt;
&lt;br /&gt;
All that needs to happen is to create theme settings in the child theme that match each of the settings in the parent theme. You will need to add matching language strings for each of these settings in the language file.&lt;br /&gt;
&lt;br /&gt;
This example shows how to do it - We are re-using the nice looking theme_boost_admin_settingspage_tabs class from boost and creating duplicate versions of each of the settings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&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;
// This is used for performance, we don&#039;t need to know about these settings on every page in Moodle, only when                      &lt;br /&gt;
// we are looking at the admin settings pages.                                                                                      &lt;br /&gt;
if ($ADMIN-&amp;gt;fulltree) {                                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Boost provides a nice setting page which splits settings onto separate tabs. We want to use it here.                         &lt;br /&gt;
    $settings = new theme_boost_admin_settingspage_tabs(&#039;themesettingphoto&#039;, get_string(&#039;configtitle&#039;, &#039;theme_photo&#039;));             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Each page is a tab - the first is the &amp;quot;General&amp;quot; tab.                                                                         &lt;br /&gt;
    $page = new admin_settingpage(&#039;theme_photo_general&#039;, get_string(&#039;generalsettings&#039;, &#039;theme_photo&#039;));                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Replicate the preset setting from boost.                                                                                     &lt;br /&gt;
    $name = &#039;theme_photo/preset&#039;;                                                                                                   &lt;br /&gt;
    $title = get_string(&#039;preset&#039;, &#039;theme_photo&#039;);                                                                                   &lt;br /&gt;
    $description = get_string(&#039;preset_desc&#039;, &#039;theme_photo&#039;);                                                                        &lt;br /&gt;
    $default = &#039;default.scss&#039;;                                                                                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // We list files in our own file area to add to the drop down. We will provide our own function to                              &lt;br /&gt;
    // load all the presets from the correct paths.                                                                                 &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    $files = $fs-&amp;gt;get_area_files($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;itemid, filepath, filename&#039;, false);                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $choices = [];                                                                                                                  &lt;br /&gt;
    foreach ($files as $file) {                                                                                                     &lt;br /&gt;
        $choices[$file-&amp;gt;get_filename()] = $file-&amp;gt;get_filename();                                                                    &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
    // These are the built in presets from Boost.                                                                                   &lt;br /&gt;
    $choices[&#039;default.scss&#039;] = &#039;default.scss&#039;;                                                                                      &lt;br /&gt;
    $choices[&#039;plain.scss&#039;] = &#039;plain.scss&#039;;                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $setting = new admin_setting_configselect($name, $title, $description, $default, $choices);                                     &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Preset files setting.                                                                                                        &lt;br /&gt;
    $name = &#039;theme_photo/presetfiles&#039;;                                                                                              &lt;br /&gt;
    $title = get_string(&#039;presetfiles&#039;,&#039;theme_photo&#039;);                                                                               &lt;br /&gt;
    $description = get_string(&#039;presetfiles_desc&#039;, &#039;theme_photo&#039;);                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;preset&#039;, 0,                                         &lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; 20, &#039;accepted_types&#039; =&amp;gt; array(&#039;.scss&#039;)));                                                               &lt;br /&gt;
    $page-&amp;gt;add($setting);     &lt;br /&gt;
&lt;br /&gt;
    // Variable $brand-color.                                                                                                       &lt;br /&gt;
    // We use an empty default value because the default colour should come from the preset.                                        &lt;br /&gt;
    $name = &#039;theme_photo/brandcolor&#039;;                                                                                               &lt;br /&gt;
    $title = get_string(&#039;brandcolor&#039;, &#039;theme_photo&#039;);                                                                               &lt;br /&gt;
    $description = get_string(&#039;brandcolor_desc&#039;, &#039;theme_photo&#039;);                                                                    &lt;br /&gt;
    $setting = new admin_setting_configcolourpicker($name, $title, $description, &#039;&#039;);                                               &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Must add the page after definiting all the settings!                                                                         &lt;br /&gt;
    $settings-&amp;gt;add($page);                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Advanced settings.                                                                                                           &lt;br /&gt;
    $page = new admin_settingpage(&#039;theme_photo_advanced&#039;, get_string(&#039;advancedsettings&#039;, &#039;theme_photo&#039;));                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Raw SCSS to include before the content.                                                                                      &lt;br /&gt;
    $setting = new admin_setting_configtextarea(&#039;theme_photo/scsspre&#039;,                                                              &lt;br /&gt;
        get_string(&#039;rawscsspre&#039;, &#039;theme_photo&#039;), get_string(&#039;rawscsspre_desc&#039;, &#039;theme_photo&#039;), &#039;&#039;, PARAM_RAW);                      &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Raw SCSS to include after the content.                                                                                       &lt;br /&gt;
    $setting = new admin_setting_configtextarea(&#039;theme_photo/scss&#039;, get_string(&#039;rawscss&#039;, &#039;theme_photo&#039;),                           &lt;br /&gt;
        get_string(&#039;rawscss_desc&#039;, &#039;theme_photo&#039;), &#039;&#039;, PARAM_RAW);                                                                  &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $settings-&amp;gt;add($page);                                                                                                          &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lang/en/theme_photo.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;
// The name of the second tab in the theme settings.                                                                                &lt;br /&gt;
$string[&#039;advancedsettings&#039;] = &#039;Advanced settings&#039;;                                                                                  &lt;br /&gt;
// The brand colour setting.                                                                                                        &lt;br /&gt;
$string[&#039;brandcolor&#039;] = &#039;Brand colour&#039;;                                                                                             &lt;br /&gt;
// The brand colour setting description.                                                                                            &lt;br /&gt;
$string[&#039;brandcolor_desc&#039;] = &#039;The accent colour.&#039;;     &lt;br /&gt;
// A description shown in the admin theme selector.                                                                                 &lt;br /&gt;
$string[&#039;choosereadme&#039;] = &#039;Theme photo is a child theme of Boost. It adds the ability to upload background photos.&#039;;                &lt;br /&gt;
// Name of the settings pages.                                                                                                      &lt;br /&gt;
$string[&#039;configtitle&#039;] = &#039;Photo settings&#039;;                                                                                          &lt;br /&gt;
// Name of the first settings tab.                                                                                                  &lt;br /&gt;
$string[&#039;generalsettings&#039;] = &#039;General settings&#039;;                                                                                    &lt;br /&gt;
// The name of our plugin.                                                                                                          &lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Photo&#039;;                                                                                                    &lt;br /&gt;
// Preset files setting.                                                                                                            &lt;br /&gt;
$string[&#039;presetfiles&#039;] = &#039;Additional theme preset files&#039;;                                                                           &lt;br /&gt;
// Preset files help text.                                                                                                          &lt;br /&gt;
$string[&#039;presetfiles_desc&#039;] = &#039;Preset files can be used to dramatically alter the appearance of the theme. See &amp;lt;a href=https://docs.moodle.org/dev/Boost_Presets&amp;gt;Boost presets&amp;lt;/a&amp;gt; for information on creating and sharing your own preset files, and see the &amp;lt;a href=http://moodle.net/boost&amp;gt;Presets repository&amp;lt;/a&amp;gt; for presets that others have shared.&#039;;&lt;br /&gt;
// Preset setting.                                                                                                                  &lt;br /&gt;
$string[&#039;preset&#039;] = &#039;Theme preset&#039;;                                                                                                 &lt;br /&gt;
// Preset help text.                                                                                                                &lt;br /&gt;
$string[&#039;preset_desc&#039;] = &#039;Pick a preset to broadly change the look of the theme.&#039;;                                                  &lt;br /&gt;
// Raw SCSS setting.                                                                                                                &lt;br /&gt;
$string[&#039;rawscss&#039;] = &#039;Raw SCSS&#039;;                                                                                                    &lt;br /&gt;
// Raw SCSS setting help text.                                                                                                      &lt;br /&gt;
$string[&#039;rawscss_desc&#039;] = &#039;Use this field to provide SCSS or CSS code which will be injected at the end of the style sheet.&#039;;       &lt;br /&gt;
// Raw initial SCSS setting.                                                                                                        &lt;br /&gt;
$string[&#039;rawscsspre&#039;] = &#039;Raw initial SCSS&#039;;                                                                                         &lt;br /&gt;
// Raw initial SCSS setting help text.                                                                                              &lt;br /&gt;
$string[&#039;rawscsspre_desc&#039;] = &#039;In this field you can provide initialising SCSS code, it will be injected before everything else. Most of the time you will use this setting to define variables.&#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;Right&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We aren&#039;t quite there yet as you will notice if you try and upload a preset file and then choose it. The &amp;quot;theme_boost_get_main_scss_content&amp;quot; function from Boost is expecting the preset files to be stored in a file area for theme_boost only. We need to add this function to our own theme and tweak it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;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. We override the boost version because          &lt;br /&gt;
// we want to allow presets uploaded to our own theme file area to be selected in the preset list.                                  &lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {                                                                                                   &lt;br /&gt;
    return theme_photo_get_main_scss_content($theme);                                                                               &lt;br /&gt;
}; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        // This preset file was fetched from the file area for theme_photo and not theme_boost (see the line above).                &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}             &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Stop and try it out ===&lt;br /&gt;
So now what is working and what isn&#039;t. Well - everything should be working and you should have a nice new theme extending boost with it&#039;s own settings pages. When Boost gets updates for bug fixes your new theme will inherit those fixes as it inherits all the SCSS and templates from theme boost. In addition your new theme will accept preset files and supports all the same features and settings as boost, ready to add more.&lt;br /&gt;
&lt;br /&gt;
== Take it further ==&lt;br /&gt;
Now we have our very nice starting point we can start changing or adding features, customising templates and output or tweaking the SCSS.&lt;br /&gt;
&lt;br /&gt;
=== Add some new settings ===&lt;br /&gt;
&lt;br /&gt;
From this point in the tutorial we will start adding features to our theme to extend it and make it AWESOME!&lt;br /&gt;
&lt;br /&gt;
Lets start with a new setting to set a background image on the login page. As you saw earlier, our theme defines it&#039;s list of settings in a file called settings.php. See [[Admin settings]] for more information about adding admin settings to any plugin. All of the different kinds of admin settings can be found in lib/adminlib.php. In our case we will want to add a setting which allows an admin to upload an image file. This is an &amp;quot;admin_setting_configstoredfile&amp;quot; and we add it to our theme by adding  this code to the settings.php file (inside the &amp;quot;if ($ADMIN-&amp;gt;fulltree) {&amp;quot; condition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    // Login page background setting.                                                                                               &lt;br /&gt;
    // We use variables for readability.                                                                                            &lt;br /&gt;
    $name = &#039;theme_photo/loginbackgroundimage&#039;;                                                                                     &lt;br /&gt;
    $title = get_string(&#039;loginbackgroundimage&#039;, &#039;theme_photo&#039;);                                                                     &lt;br /&gt;
    $description = get_string(&#039;loginbackgroundimage_desc&#039;, &#039;theme_photo&#039;);                                                          &lt;br /&gt;
    // This creates the new setting.                                                                                                &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;loginbackgroundimage&#039;);                             &lt;br /&gt;
    // This means that theme caches will automatically be cleared when this setting is changed.                                     &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    // We always have to add the setting to a page for it to have any effect.                                                       &lt;br /&gt;
    $page-&amp;gt;add($setting);       &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to add new lang strings to our language file.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lang/en/theme_photo.php&amp;quot;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Background image for login page.                                                                                                 &lt;br /&gt;
$string[&#039;loginbackgroundimage&#039;] = &#039;Login page background image&#039;;                                                                    &lt;br /&gt;
// Background image for login page.                                                                                                 &lt;br /&gt;
$string[&#039;loginbackgroundimage_desc&#039;] = &#039;An image that will be stretched to fill the background of the login page.&#039;;                 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we have a new setting that lets us upload a file - but it doesn&#039;t actually do anything yet. We need to update the theme to set this image background on the login page.&lt;br /&gt;
&lt;br /&gt;
In order to change the SCSS for our theme we will add 2 additional SCSS files and include them before and after our main scss.&lt;br /&gt;
&lt;br /&gt;
We already have a function in our lib.php file which fetches the main SCSS for our theme. This is a good point to include additional SCSS files. We can add 2 lines to the end of this function to achieve this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        // This preset file was fetched from the file area for theme_photo and not theme_boost (see the line above).                &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                               &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/photo/scss/pre.scss&#039;);                                                         &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/photo/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;
&#039;&#039;scss/pre.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// Pre SCSS for the theme.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;scss/post.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// Post SCSS for the theme.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why do we use pre and post SCSS? ====&lt;br /&gt;
SCSS/SASS is a powerful language for creating CSS. It supports variables, functions, loops just like php. For lots of information and an introduction to SCSS read about [https://en.wikipedia.org/wiki/Sass_(stylesheet_language) Sass on wikipedia]. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pre SCSS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In Boost we use many variables when creating style rules.&lt;br /&gt;
&lt;br /&gt;
When declaring a variable in SCSS - it is best practice to define it like this:&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
$mycoolcolour: #FF0 !default;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this means is - if this variable is not defined already - set it to the hex value &#039;#FF0&#039;;&lt;br /&gt;
&lt;br /&gt;
So by setting this variable in some PRE scss we can override the default the value of this variable everywhere it is used. Boost is built with the [https://v4-alpha.getbootstrap.com/ Bootstrap 4 (Alpha 4)] CSS Framework. This is a framework which uses SCSS to provide many extremely useful layouts and components which can be reused without adding specific CSS rules to style every page. Because bootstrap consistently uses variables we can customise many of these components easily by setting the value of the variables before we include the Bootstrap SCSS files.&lt;br /&gt;
&lt;br /&gt;
Many variables are available in /theme/boost/scss/bootstrap/_variables.scss - as an example we can change the look of all buttons and input fields with this one variable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
$border-radius: 8px;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Post SCSS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Post SCSS is useful for defining full CSS rules. Because they are included last, they override any previous matching selector with the same [https://en.wikipedia.org/wiki/Cascading_Style_Sheets#Specificity Specificity].&lt;br /&gt;
&lt;br /&gt;
=== Tips for customising Moodle with SCSS (or CSS) ===&lt;br /&gt;
Some handy things to know when you are new to theming is that Moodle adds some classes to every page that helps you target a specific page or set of pages with some style rules. &lt;br /&gt;
&lt;br /&gt;
If you inspect a moodle page and look at the body tag you will see a long list of classes e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
&amp;lt;body id=&amp;quot;page-course-view-weeks&amp;quot; class=&amp;quot;format-weeks  path-course path-course-view safari dir-ltr lang-en yui-skin-sam yui3-skin-sam damyon-per-in-moodle-com--stable_master pagelayout-course course-11 context-497 category-1 drawer-open-left jsenabled&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see from this example that each page gets an id. This is a simplified representation of the current page in the navigation. In this example we are looking at the course page and this course is using the weeks format. &lt;br /&gt;
&lt;br /&gt;
The classes on the body tag can also be used to target a page or set of pages.&lt;br /&gt;
* &amp;lt;code&amp;gt;format-weeks&amp;lt;/code&amp;gt; The course format&lt;br /&gt;
* &amp;lt;code&amp;gt;path-course path-course-view&amp;lt;/code&amp;gt; The parts of the bread-crumb leading up to the current page (The current page is what goes in the id)&lt;br /&gt;
* &amp;lt;code&amp;gt;safari&amp;lt;/code&amp;gt; Some server side guessing of the browser type - it&#039;s not accurate so I would not rely on it&lt;br /&gt;
* &amp;lt;code&amp;gt;dir-ltr&amp;lt;/code&amp;gt; The direction of the current language for the page ( dir-rtl for RTL languages )&lt;br /&gt;
* &amp;lt;code&amp;gt;lang-en&amp;lt;/code&amp;gt; The current language of the page&lt;br /&gt;
* &amp;lt;code&amp;gt;yui*&amp;lt;/code&amp;gt; Legacy yui classes - ignore these&lt;br /&gt;
* &amp;lt;code&amp;gt;damyon-per-in-moodle-com--stable_master&amp;lt;/code&amp;gt; The current hostname for the site + the site name&lt;br /&gt;
* &amp;lt;code&amp;gt;pagelayout-course&amp;lt;/code&amp;gt; The layout type for the current page&lt;br /&gt;
* &amp;lt;code&amp;gt;course-11&amp;lt;/code&amp;gt; The id of the current course&lt;br /&gt;
* &amp;lt;code&amp;gt;context-497&amp;lt;/code&amp;gt; The current context id&lt;br /&gt;
* &amp;lt;code&amp;gt;category-1&amp;lt;/code&amp;gt; The category for the current course&lt;br /&gt;
* &amp;lt;code&amp;gt;drawer-open-left&amp;lt;/code&amp;gt; Added / removed when the navigation drawer is opened / closed in Boost&lt;br /&gt;
* &amp;lt;code&amp;gt;jsenabled&amp;lt;/code&amp;gt; True if the browser supports javascript&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Themes_overview#.3Cbody.3E_CSS_id_and_classes Read about Body id and classes].&lt;br /&gt;
&lt;br /&gt;
In our example the page layout is the most useful here as we have a specific page layout for login pages. We can now craft a rule that applies a background image only to login pages using &amp;quot;body.pagelayout-login&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== How do we refer to an image in SCSS ? ===&lt;br /&gt;
So now we can add a rule to the post.scss which will set the background image for the login page. First we need to know how to construct a url to the background images from our stylesheet. &lt;br /&gt;
&lt;br /&gt;
In stylesheets in Moodle we can use a special pix tag to refer to images from our theme. The rule to attach the background image looks like this:&lt;br /&gt;
&#039;&#039;scss/post.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
body.pagelayout-login {                                                                                                             &lt;br /&gt;
    background-image: url([[pix:theme_photo|loginbackgroundimage]]);                                                                &lt;br /&gt;
    background-size: cover;                                                                                                         &lt;br /&gt;
}                          &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are 2 important parts to this tag (the bit in square brackets). The first is &amp;quot;theme_photo&amp;quot;. In this case we are passing a component name, the image serving code in theme_config::resolve_image_location() will then look for an image file in several locations. One of these is in &amp;quot;$CFG-&amp;gt;dataroot/pix_plugins/$type/$plugin/$image&amp;quot;. We can use this to make sure the image gets served correctly by copying the file saved in the setting to this location every time it is updated. (There is an alterative way we could do this by implementing pluginfile.php in our theme - which you can read about in the [[File API]] ).&lt;br /&gt;
&lt;br /&gt;
If we had just passed the value &amp;quot;theme&amp;quot; the image serving code would have looked for the image in the &amp;quot;pix&amp;quot; folder of our theme.&lt;br /&gt;
&lt;br /&gt;
So - we need this final change to copy the image file into our dataroot each time the setting is changed.&lt;br /&gt;
&lt;br /&gt;
In the settings file we will update the callback to a new function which we will define in our lib.php.&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    // Login page background setting.                                                                                               &lt;br /&gt;
    // We use variables for readability.                                                                                            &lt;br /&gt;
    $name = &#039;theme_photo/loginbackgroundimage&#039;;                                                                                     &lt;br /&gt;
    $title = get_string(&#039;loginbackgroundimage&#039;, &#039;theme_photo&#039;);                                                                     &lt;br /&gt;
    $description = get_string(&#039;loginbackgroundimage_desc&#039;, &#039;theme_photo&#039;);                                                          &lt;br /&gt;
    // This creates the new setting.                                                                                                &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;loginbackgroundimage&#039;);                             &lt;br /&gt;
    // This function will copy the image into the data_root location it can be served from.                                         &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_photo_update_settings_images&#039;);                                                            &lt;br /&gt;
    // We always have to add the setting to a page for it to have any effect.                                                       &lt;br /&gt;
    $page-&amp;gt;add($setting);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_update_settings_images($settingname) {                                                                         &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // The setting name that was updated comes as a string like &#039;s_theme_photo_loginbackgroundimage&#039;.                               &lt;br /&gt;
    // We split it on &#039;_&#039; characters.                                                                                               &lt;br /&gt;
    $parts = explode(&#039;_&#039;, $settingname);                                                                                            &lt;br /&gt;
    // And get the last one to get the setting name..                                                                               &lt;br /&gt;
    $settingname = end($parts);                                                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Admin settings are stored in system context.                                                                                 &lt;br /&gt;
    $syscontext = context_system::instance();                                                                                       &lt;br /&gt;
    // This is the component name the setting is stored in.                                                                         &lt;br /&gt;
    $component = &#039;theme_photo&#039;;                                                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // This is the value of the admin setting which is the filename of the uploaded file.                                           &lt;br /&gt;
    $filename = get_config($component, $settingname);                                                                               &lt;br /&gt;
    // We extract the file extension because we want to preserve it.                                                                &lt;br /&gt;
    $extension = substr($filename, strrpos($filename, &#039;.&#039;) + 1);                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // This is the path in the moodle internal file system.                                                                         &lt;br /&gt;
    $fullpath = &amp;quot;/{$syscontext-&amp;gt;id}/{$component}/{$settingname}/0{$filename}&amp;quot;;                                                      &lt;br /&gt;
    // Get an instance of the moodle file storage.                                                                                  &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    // This is an efficient way to get a file if we know the exact path.                                                            &lt;br /&gt;
    if ($file = $fs-&amp;gt;get_file_by_hash(sha1($fullpath))) {                                                                           &lt;br /&gt;
        // We got the stored file - copy it to dataroot.                                                                            &lt;br /&gt;
        // This location matches the searched for location in theme_config::resolve_image_location.                                 &lt;br /&gt;
        $pathname = $CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039; . $settingname . &#039;.&#039; . $extension;                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // This pattern matches any previous files with maybe different file extensions.                                            &lt;br /&gt;
        $pathpattern = $CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039; . $settingname . &#039;.*&#039;;                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Make sure this dir exists.                                                                                               &lt;br /&gt;
        @mkdir($CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039;, $CFG-&amp;gt;directorypermissions, true);                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Delete any existing files for this setting.                                                                              &lt;br /&gt;
        foreach (glob($pathpattern) as $filename) {                                                                                 &lt;br /&gt;
            @unlink($filename);                                                                                                     &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Copy the current file to this location.                                                                                  &lt;br /&gt;
        $file-&amp;gt;copy_content_to($pathname);                                                                                          &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Reset theme caches.                                                                                                          &lt;br /&gt;
    theme_reset_all_caches();                                                                                                       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I won&#039;t show it here - but it is now easy to add a new background image setting for every layout type. I can re-use this theme_photo_update_settings_images callback for each one - so all I have to do is add the setting to the settings.php file, add the SCSS rule to the scss/post.scss file and add the lang strings to the language file.&lt;br /&gt;
&lt;br /&gt;
Thats 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>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=55769</id>
		<title>Creating a theme based on boost</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=55769"/>
		<updated>2019-03-22T01:46:39Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.2}}&lt;br /&gt;
{{Template:Themes}}&lt;br /&gt;
&lt;br /&gt;
This is a tutorial for how to create a new theme in Moodle 3.2.&lt;br /&gt;
&lt;br /&gt;
Moodle 3.2 includes a new core theme named &amp;quot;Boost&amp;quot; which is a great starting point for themers wanting to build a modern Moodle theme utilising all the latest features available to themes in Moodle.  If you aren&#039;t sure where to start, then START HERE!  :-)&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 a working theme named &amp;quot;theme_photo&amp;quot; you can download it or view the source code for it here: https://github.com/damyon/moodle-theme_photo&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 moodle.org/plugins can save you a lot of work renaming things later.&lt;br /&gt;
&lt;br /&gt;
Lets call our new example theme &amp;quot;photo&amp;quot; as we will add some settings to allow &amp;quot;photos&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 we can start creating our 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/photo/&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/photo/version.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;
// This is the version of the plugin.                                                                                               &lt;br /&gt;
$plugin-&amp;gt;version = &#039;2016102100&#039;;                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
// This is the version of Moodle this plugin requires.                                                                              &lt;br /&gt;
$plugin-&amp;gt;requires = &#039;2016070700&#039;;                                                                                                   &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_photo&#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_boost&#039; =&amp;gt; &#039;2016102100&#039;                                                                                                   &lt;br /&gt;
];                                                                              &lt;br /&gt;
&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/photo/lang/en/theme_photo.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 photo is a child theme of Boost. 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;Photo&#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;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;
&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;
// $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;photo&#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 /style/ 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_boost because it provides a great starting point for SCSS bootstrap4   &lt;br /&gt;
// themes. We could 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;];                                                                                                        &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. Boost         &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 Boost based themes because Boost           &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;
// This is a list of blocks that are required to exist on all pages for this theme to function correctly. For example               &lt;br /&gt;
// bootstrap base requires the settings and navigation blocks because otherwise there would be no way to navigate to all the        &lt;br /&gt;
// pages in Moodle. Boost does not require these blocks because it provides other ways to navigate built into the theme.            &lt;br /&gt;
$THEME-&amp;gt;requiredblocks = &#039;&#039;;   &lt;br /&gt;
&lt;br /&gt;
// This is a feature that tells the blocks library not to use the &amp;quot;Add a block&amp;quot; block. We don&#039;t want this in boost based themes because&lt;br /&gt;
// it forces a block region into the page when editing is enabled and it takes up too much room.&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;
=== 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 Boost. 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. If you choose a different preset in Boost - it is not applied in this child theme.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warningbox&amp;quot;&amp;gt;&lt;br /&gt;
Note: make sure your config.php file contains $THEME-&amp;gt;hidefromselector = false; (or at least set to false) or else, your theme wont show up in theme selector.&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== What if I want the settings too? ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;warningbox&amp;quot;&amp;gt;&lt;br /&gt;
This section is included for completeness - but it is not recommended for themes to utilise settings from their parents. To find out how to duplicate the settings from the parent theme so they operate independently skip to [[#Duplicate the settings from Boost]].&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If I want the settings from Boost to apply to my child theme as well I need to know a bit about how each of the settings in Boost is applied to make them work in my child theme.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Setting 1 - preset.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;preset&amp;quot; file is the file that is used as the main file for scss compilation. In Boost this is controlled by the theme config value:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&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;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_boost&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this function is doing is checking for a theme setting &amp;quot;preset&amp;quot; and either fetching the file from Moodles internal file storage, or from the /preset/ folder. The function then returns the contents of this file.&lt;br /&gt;
&lt;br /&gt;
It does not automatically work for our child theme because we have no setting named &amp;quot;preset&amp;quot; in our child theme and this code is not searching the theme parents for the setting. If we wanted it to apply we could do this in our child theme:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This setting defines the main scss file for our theme to be compiled. We could set it to a static file in the scss folder or to a function which returns the SCSS based on theme settings.&lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {&lt;br /&gt;
&lt;br /&gt;
    // We need to load the config for our parent theme because that is where the preset setting is defined.&lt;br /&gt;
    $parentconfig = theme_config::load(&#039;boost&#039;);&lt;br /&gt;
    // Call a function from our parent themes lib.php file to fetch the content of the themes main SCSS file based on it&#039;s own config, not ours.&lt;br /&gt;
    return theme_boost_get_main_scss_content($parentconfig);&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Settings 2+3 brandcolor + scsspre&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The way these settings work is they generate a chunk of SCSS to be prepended to the main scss file. In boost they work like this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_boost_get_pre_scss&#039;; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_pre_scss($theme) {                                                                                         &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $configurable = [                                                                                                               &lt;br /&gt;
        // Config key =&amp;gt; [variableName, ...].                                                                                       &lt;br /&gt;
        &#039;brandcolor&#039; =&amp;gt; [&#039;brand-primary&#039;],                                                                                          &lt;br /&gt;
    ];                                                                                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Prepend variables first.                                                                                                     &lt;br /&gt;
    foreach ($configurable as $configkey =&amp;gt; $targets) {                                                                             &lt;br /&gt;
        $value = isset($theme-&amp;gt;settings-&amp;gt;{$configkey}) ? $theme-&amp;gt;settings-&amp;gt;{$configkey} : null;                                     &lt;br /&gt;
        if (empty($value)) {                                                                                                        &lt;br /&gt;
            continue;                                                                                                               &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        array_map(function($target) use (&amp;amp;$scss, $value) {                                                                          &lt;br /&gt;
            $scss .= &#039;$&#039; . $target . &#039;: &#039; . $value . &amp;quot;;\n&amp;quot;;                                                                         &lt;br /&gt;
        }, (array) $targets);                                                                                                       &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Prepend pre-scss.                                                                                                            &lt;br /&gt;
    if (!empty($theme-&amp;gt;settings-&amp;gt;scsspre)) {                                                                                        &lt;br /&gt;
        $scss .= $theme-&amp;gt;settings-&amp;gt;scsspre;                                                                                         &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}  &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this code is doing is: &lt;br /&gt;
* looping over a list of theme settings that map to a SCSS variable and building some SCSS to initialise that variable from the setting. In Boost there is only one * brandprimary - but if we wanted to expose more bootstrap variables as theme settings we could use this function as a template in our child theme and add more settings to the $configurable array.&lt;br /&gt;
* Adding all of the raw SCSS from the scsspre theme setting&lt;br /&gt;
* Returning the whole thing as a string to be added before the main scss file.&lt;br /&gt;
&lt;br /&gt;
If we want this code to work in our child theme, using the settings from Boost we could do this:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This is a function that returns some SCSS as a string to prepend to the main SCSS file.                                          &lt;br /&gt;
$THEME-&amp;gt;prescsscallback = &#039;theme_photo_get_pre_scss&#039;;               &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Function to return the SCSS to prepend to our main SCSS for this theme.&lt;br /&gt;
// Note the function name starts with the component name because this is a global function and we don&#039;t want namespace clashes.&lt;br /&gt;
function theme_photo_get_pre_scss($theme) {&lt;br /&gt;
    // Load the settings from the parent.                                                                                           &lt;br /&gt;
    $theme = theme_config::load(&#039;boost&#039;);                                                                                           &lt;br /&gt;
    // Call the parent themes get_pre_scss function.                                                                                &lt;br /&gt;
    return theme_boost_get_pre_scss($theme);                         &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Setting 4 scss (post)&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The final setting from Boost is a raw text field which adds SCSS to the end of the main SCSS file. This is a useful place to add style rules as they will override previously defined styles with the same specificity. It is applied in Boost by the following lines:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;theme_boost/config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_boost_get_extra_scss&#039;; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&#039;&#039;theme_boost/lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_boost_get_extra_scss($theme) {                                                                                       &lt;br /&gt;
    return !empty($theme-&amp;gt;settings-&amp;gt;scss) ? $theme-&amp;gt;settings-&amp;gt;scss : &#039;&#039;;                                                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is just returning the value of the setting as a string.&lt;br /&gt;
&lt;br /&gt;
To make this setting apply in our child theme too - we use similar code to the previous sections.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;config.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// This is a function that returns some SCSS as a string to prepend to the main SCSS file.                                          &lt;br /&gt;
$THEME-&amp;gt;extrascsscallback = &#039;theme_photo_get_extra_scss&#039;;               &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Function to return the SCSS to append to our main SCSS for this theme.&lt;br /&gt;
// Note the function name starts with the component name because this is a global function and we don&#039;t want namespace clashes.&lt;br /&gt;
function theme_photo_get_extra_scss($theme) {&lt;br /&gt;
    // Load the settings from the parent.                                                                                           &lt;br /&gt;
    $theme = theme_config::load(&#039;boost&#039;);                                                                                           &lt;br /&gt;
    // Call the parent themes get_extra_scss function.                                                                                &lt;br /&gt;
    return theme_boost_get_extra_scss($theme);                         &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Duplicate the settings from Boost  ===&lt;br /&gt;
&lt;br /&gt;
This is the recommended way to extend boost as your child theme will not be affected by changes to the Boost settings, and both themes can be in use with different settings applied.&lt;br /&gt;
&lt;br /&gt;
All that needs to happen is to create theme settings in the child theme that match each of the settings in the parent theme. You will need to add matching language strings for each of these settings in the language file.&lt;br /&gt;
&lt;br /&gt;
This example shows how to do it - We are re-using the nice looking theme_boost_admin_settingspage_tabs class from boost and creating duplicate versions of each of the settings.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&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;
// This is used for performance, we don&#039;t need to know about these settings on every page in Moodle, only when                      &lt;br /&gt;
// we are looking at the admin settings pages.                                                                                      &lt;br /&gt;
if ($ADMIN-&amp;gt;fulltree) {                                                                                                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Boost provides a nice setting page which splits settings onto separate tabs. We want to use it here.                         &lt;br /&gt;
    $settings = new theme_boost_admin_settingspage_tabs(&#039;themesettingphoto&#039;, get_string(&#039;configtitle&#039;, &#039;theme_photo&#039;));             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Each page is a tab - the first is the &amp;quot;General&amp;quot; tab.                                                                         &lt;br /&gt;
    $page = new admin_settingpage(&#039;theme_photo_general&#039;, get_string(&#039;generalsettings&#039;, &#039;theme_photo&#039;));                             &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Replicate the preset setting from boost.                                                                                     &lt;br /&gt;
    $name = &#039;theme_photo/preset&#039;;                                                                                                   &lt;br /&gt;
    $title = get_string(&#039;preset&#039;, &#039;theme_photo&#039;);                                                                                   &lt;br /&gt;
    $description = get_string(&#039;preset_desc&#039;, &#039;theme_photo&#039;);                                                                        &lt;br /&gt;
    $default = &#039;default.scss&#039;;                                                                                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // We list files in our own file area to add to the drop down. We will provide our own function to                              &lt;br /&gt;
    // load all the presets from the correct paths.                                                                                 &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    $files = $fs-&amp;gt;get_area_files($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;itemid, filepath, filename&#039;, false);                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $choices = [];                                                                                                                  &lt;br /&gt;
    foreach ($files as $file) {                                                                                                     &lt;br /&gt;
        $choices[$file-&amp;gt;get_filename()] = $file-&amp;gt;get_filename();                                                                    &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
    // These are the built in presets from Boost.                                                                                   &lt;br /&gt;
    $choices[&#039;default.scss&#039;] = &#039;default.scss&#039;;                                                                                      &lt;br /&gt;
    $choices[&#039;plain.scss&#039;] = &#039;plain.scss&#039;;                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $setting = new admin_setting_configselect($name, $title, $description, $default, $choices);                                     &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Preset files setting.                                                                                                        &lt;br /&gt;
    $name = &#039;theme_photo/presetfiles&#039;;                                                                                              &lt;br /&gt;
    $title = get_string(&#039;presetfiles&#039;,&#039;theme_photo&#039;);                                                                               &lt;br /&gt;
    $description = get_string(&#039;presetfiles_desc&#039;, &#039;theme_photo&#039;);                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;preset&#039;, 0,                                         &lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; 20, &#039;accepted_types&#039; =&amp;gt; array(&#039;.scss&#039;)));                                                               &lt;br /&gt;
    $page-&amp;gt;add($setting);     &lt;br /&gt;
&lt;br /&gt;
    // Variable $brand-color.                                                                                                       &lt;br /&gt;
    // We use an empty default value because the default colour should come from the preset.                                        &lt;br /&gt;
    $name = &#039;theme_photo/brandcolor&#039;;                                                                                               &lt;br /&gt;
    $title = get_string(&#039;brandcolor&#039;, &#039;theme_photo&#039;);                                                                               &lt;br /&gt;
    $description = get_string(&#039;brandcolor_desc&#039;, &#039;theme_photo&#039;);                                                                    &lt;br /&gt;
    $setting = new admin_setting_configcolourpicker($name, $title, $description, &#039;&#039;);                                               &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Must add the page after definiting all the settings!                                                                         &lt;br /&gt;
    $settings-&amp;gt;add($page);                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Advanced settings.                                                                                                           &lt;br /&gt;
    $page = new admin_settingpage(&#039;theme_photo_advanced&#039;, get_string(&#039;advancedsettings&#039;, &#039;theme_photo&#039;));                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Raw SCSS to include before the content.                                                                                      &lt;br /&gt;
    $setting = new admin_setting_configtextarea(&#039;theme_photo/scsspre&#039;,                                                              &lt;br /&gt;
        get_string(&#039;rawscsspre&#039;, &#039;theme_photo&#039;), get_string(&#039;rawscsspre_desc&#039;, &#039;theme_photo&#039;), &#039;&#039;, PARAM_RAW);                      &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Raw SCSS to include after the content.                                                                                       &lt;br /&gt;
    $setting = new admin_setting_configtextarea(&#039;theme_photo/scss&#039;, get_string(&#039;rawscss&#039;, &#039;theme_photo&#039;),                           &lt;br /&gt;
        get_string(&#039;rawscss_desc&#039;, &#039;theme_photo&#039;), &#039;&#039;, PARAM_RAW);                                                                  &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    $page-&amp;gt;add($setting);                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $settings-&amp;gt;add($page);                                                                                                          &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lang/en/theme_photo.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;
// The name of the second tab in the theme settings.                                                                                &lt;br /&gt;
$string[&#039;advancedsettings&#039;] = &#039;Advanced settings&#039;;                                                                                  &lt;br /&gt;
// The brand colour setting.                                                                                                        &lt;br /&gt;
$string[&#039;brandcolor&#039;] = &#039;Brand colour&#039;;                                                                                             &lt;br /&gt;
// The brand colour setting description.                                                                                            &lt;br /&gt;
$string[&#039;brandcolor_desc&#039;] = &#039;The accent colour.&#039;;     &lt;br /&gt;
// A description shown in the admin theme selector.                                                                                 &lt;br /&gt;
$string[&#039;choosereadme&#039;] = &#039;Theme photo is a child theme of Boost. It adds the ability to upload background photos.&#039;;                &lt;br /&gt;
// Name of the settings pages.                                                                                                      &lt;br /&gt;
$string[&#039;configtitle&#039;] = &#039;Photo settings&#039;;                                                                                          &lt;br /&gt;
// Name of the first settings tab.                                                                                                  &lt;br /&gt;
$string[&#039;generalsettings&#039;] = &#039;General settings&#039;;                                                                                    &lt;br /&gt;
// The name of our plugin.                                                                                                          &lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Photo&#039;;                                                                                                    &lt;br /&gt;
// Preset files setting.                                                                                                            &lt;br /&gt;
$string[&#039;presetfiles&#039;] = &#039;Additional theme preset files&#039;;                                                                           &lt;br /&gt;
// Preset files help text.                                                                                                          &lt;br /&gt;
$string[&#039;presetfiles_desc&#039;] = &#039;Preset files can be used to dramatically alter the appearance of the theme. See &amp;lt;a href=https://docs.moodle.org/dev/Boost_Presets&amp;gt;Boost presets&amp;lt;/a&amp;gt; for information on creating and sharing your own preset files, and see the &amp;lt;a href=http://moodle.net/boost&amp;gt;Presets repository&amp;lt;/a&amp;gt; for presets that others have shared.&#039;;&lt;br /&gt;
// Preset setting.                                                                                                                  &lt;br /&gt;
$string[&#039;preset&#039;] = &#039;Theme preset&#039;;                                                                                                 &lt;br /&gt;
// Preset help text.                                                                                                                &lt;br /&gt;
$string[&#039;preset_desc&#039;] = &#039;Pick a preset to broadly change the look of the theme.&#039;;                                                  &lt;br /&gt;
// Raw SCSS setting.                                                                                                                &lt;br /&gt;
$string[&#039;rawscss&#039;] = &#039;Raw SCSS&#039;;                                                                                                    &lt;br /&gt;
// Raw SCSS setting help text.                                                                                                      &lt;br /&gt;
$string[&#039;rawscss_desc&#039;] = &#039;Use this field to provide SCSS or CSS code which will be injected at the end of the style sheet.&#039;;       &lt;br /&gt;
// Raw initial SCSS setting.                                                                                                        &lt;br /&gt;
$string[&#039;rawscsspre&#039;] = &#039;Raw initial SCSS&#039;;                                                                                         &lt;br /&gt;
// Raw initial SCSS setting help text.                                                                                              &lt;br /&gt;
$string[&#039;rawscsspre_desc&#039;] = &#039;In this field you can provide initialising SCSS code, it will be injected before everything else. Most of the time you will use this setting to define variables.&#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;Right&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We aren&#039;t quite there yet as you will notice if you try and upload a preset file and then choose it. The &amp;quot;theme_boost_get_main_scss_content&amp;quot; function from Boost is expecting the preset files to be stored in a file area for theme_boost only. We need to add this function to our own theme and tweak it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;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. We override the boost version because          &lt;br /&gt;
// we want to allow presets uploaded to our own theme file area to be selected in the preset list.                                  &lt;br /&gt;
$THEME-&amp;gt;scss = function($theme) {                                                                                                   &lt;br /&gt;
    return theme_photo_get_main_scss_content($theme);                                                                               &lt;br /&gt;
}; &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        // This preset file was fetched from the file area for theme_photo and not theme_boost (see the line above).                &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return $scss;                                                                                                                   &lt;br /&gt;
}             &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Stop and try it out ===&lt;br /&gt;
So now what is working and what isn&#039;t. Well - everything should be working and you should have a nice new theme extending boost with it&#039;s own settings pages. When Boost gets updates for bug fixes your new theme will inherit those fixes as it inherits all the SCSS and templates from theme boost. In addition your new theme will accept preset files and supports all the same features and settings as boost, ready to add more.&lt;br /&gt;
&lt;br /&gt;
== Take it further ==&lt;br /&gt;
Now we have our very nice starting point we can start changing or adding features, customising templates and output or tweaking the SCSS.&lt;br /&gt;
&lt;br /&gt;
=== Add some new settings ===&lt;br /&gt;
&lt;br /&gt;
From this point in the tutorial we will start adding features to our theme to extend it and make it AWESOME!&lt;br /&gt;
&lt;br /&gt;
Lets start with a new setting to set a background image on the login page. As you saw earlier, our theme defines it&#039;s list of settings in a file called settings.php. See [[Admin settings]] for more information about adding admin settings to any plugin. All of the different kinds of admin settings can be found in lib/adminlib.php. In our case we will want to add a setting which allows an admin to upload an image file. This is an &amp;quot;admin_setting_configstoredfile&amp;quot; and we add it to our theme by adding  this code to the settings.php file (inside the &amp;quot;if ($ADMIN-&amp;gt;fulltree) {&amp;quot; condition.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    // Login page background setting.                                                                                               &lt;br /&gt;
    // We use variables for readability.                                                                                            &lt;br /&gt;
    $name = &#039;theme_photo/loginbackgroundimage&#039;;                                                                                     &lt;br /&gt;
    $title = get_string(&#039;loginbackgroundimage&#039;, &#039;theme_photo&#039;);                                                                     &lt;br /&gt;
    $description = get_string(&#039;loginbackgroundimage_desc&#039;, &#039;theme_photo&#039;);                                                          &lt;br /&gt;
    // This creates the new setting.                                                                                                &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;loginbackgroundimage&#039;);                             &lt;br /&gt;
    // This means that theme caches will automatically be cleared when this setting is changed.                                     &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_reset_all_caches&#039;);                                                                        &lt;br /&gt;
    // We always have to add the setting to a page for it to have any effect.                                                       &lt;br /&gt;
    $page-&amp;gt;add($setting);       &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We also need to add new lang strings to our language file.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;lang/en/theme_photo.php&amp;quot;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Background image for login page.                                                                                                 &lt;br /&gt;
$string[&#039;loginbackgroundimage&#039;] = &#039;Login page background image&#039;;                                                                    &lt;br /&gt;
// Background image for login page.                                                                                                 &lt;br /&gt;
$string[&#039;loginbackgroundimage_desc&#039;] = &#039;An image that will be stretched to fill the background of the login page.&#039;;                 &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we have a new setting that lets us upload a file - but it doesn&#039;t actually do anything yet. We need to update the theme to set this image background on the login page.&lt;br /&gt;
&lt;br /&gt;
In order to change the SCSS for our theme we will add 2 additional SCSS files and include them before and after our main scss.&lt;br /&gt;
&lt;br /&gt;
We already have a function in our lib.php file which fetches the main SCSS for our theme. This is a good point to include additional SCSS files. We can add 2 lines to the end of this function to achieve this.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_get_main_scss_content($theme) {                                                                                &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $scss = &#039;&#039;;                                                                                                                     &lt;br /&gt;
    $filename = !empty($theme-&amp;gt;settings-&amp;gt;preset) ? $theme-&amp;gt;settings-&amp;gt;preset : null;                                                 &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $context = context_system::instance();                                                                                          &lt;br /&gt;
    if ($filename == &#039;default.scss&#039;) {                                                                                              &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    } else if ($filename == &#039;plain.scss&#039;) {                                                                                         &lt;br /&gt;
        // We still load the default preset files directly from the boost theme. No sense in duplicating them.                      &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/plain.scss&#039;);                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    } else if ($filename &amp;amp;&amp;amp; ($presetfile = $fs-&amp;gt;get_file($context-&amp;gt;id, &#039;theme_photo&#039;, &#039;preset&#039;, 0, &#039;/&#039;, $filename))) {              &lt;br /&gt;
        // This preset file was fetched from the file area for theme_photo and not theme_boost (see the line above).                &lt;br /&gt;
        $scss .= $presetfile-&amp;gt;get_content();                                                                                        &lt;br /&gt;
    } else {                                                                                                                        &lt;br /&gt;
        // Safety fallback - maybe new installs etc.                                                                                &lt;br /&gt;
        $scss .= file_get_contents($CFG-&amp;gt;dirroot . &#039;/theme/boost/scss/preset/default.scss&#039;);                                        &lt;br /&gt;
    }                                                                                                                               &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/photo/scss/pre.scss&#039;);                                                         &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/photo/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;
&#039;&#039;scss/pre.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// Pre SCSS for the theme.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;scss/post.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// Post SCSS for the theme.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Why do we use pre and post SCSS? ====&lt;br /&gt;
SCSS/SASS is a powerful language for creating CSS. It supports variables, functions, loops just like php. For lots of information and an introduction to SCSS read about [https://en.wikipedia.org/wiki/Sass_(stylesheet_language) Sass on wikipedia]. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Pre SCSS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In Boost we use many variables when creating style rules.&lt;br /&gt;
&lt;br /&gt;
When declaring a variable in SCSS - it is best practice to define it like this:&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
$mycoolcolour: #FF0 !default;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What this means is - if this variable is not defined already - set it to the hex value &#039;#FF0&#039;;&lt;br /&gt;
&lt;br /&gt;
So by setting this variable in some PRE scss we can override the default the value of this variable everywhere it is used. Boost is built with the [https://v4-alpha.getbootstrap.com/ Bootstrap 4 (Alpha 4)] CSS Framework. This is a framework which uses SCSS to provide many extremely useful layouts and components which can be reused without adding specific CSS rules to style every page. Because bootstrap consistently uses variables we can customise many of these components easily by setting the value of the variables before we include the Bootstrap SCSS files.&lt;br /&gt;
&lt;br /&gt;
Many variables are available in /theme/boost/scss/bootstrap/_variables.scss - as an example we can change the look of all buttons and input fields with this one variable:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
$border-radius: 8px;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Post SCSS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Post SCSS is useful for defining full CSS rules. Because they are included last, they override any previous matching selector with the same [https://en.wikipedia.org/wiki/Cascading_Style_Sheets#Specificity Specificity].&lt;br /&gt;
&lt;br /&gt;
=== Tips for customising Moodle with SCSS (or CSS) ===&lt;br /&gt;
Some handy things to know when you are new to theming is that Moodle adds some classes to every page that helps you target a specific page or set of pages with some style rules. &lt;br /&gt;
&lt;br /&gt;
If you inspect a moodle page and look at the body tag you will see a long list of classes e.g.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code html&amp;gt;&lt;br /&gt;
&amp;lt;body id=&amp;quot;page-course-view-weeks&amp;quot; class=&amp;quot;format-weeks  path-course path-course-view safari dir-ltr lang-en yui-skin-sam yui3-skin-sam damyon-per-in-moodle-com--stable_master pagelayout-course course-11 context-497 category-1 drawer-open-left jsenabled&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You can see from this example that each page gets an id. This is a simplified representation of the current page in the navigation. In this example we are looking at the course page and this course is using the weeks format. &lt;br /&gt;
&lt;br /&gt;
The classes on the body tag can also be used to target a page or set of pages.&lt;br /&gt;
* &amp;lt;code&amp;gt;format-weeks&amp;lt;/code&amp;gt; The course format&lt;br /&gt;
* &amp;lt;code&amp;gt;path-course path-course-view&amp;lt;/code&amp;gt; The parts of the bread-crumb leading up to the current page (The current page is what goes in the id)&lt;br /&gt;
* &amp;lt;code&amp;gt;safari&amp;lt;/code&amp;gt; Some server side guessing of the browser type - it&#039;s not accurate so I would not rely on it&lt;br /&gt;
* &amp;lt;code&amp;gt;dir-ltr&amp;lt;/code&amp;gt; The direction of the current language for the page ( dir-rtl for RTL languages )&lt;br /&gt;
* &amp;lt;code&amp;gt;lang-en&amp;lt;/code&amp;gt; The current language of the page&lt;br /&gt;
* &amp;lt;code&amp;gt;yui*&amp;lt;/code&amp;gt; Legacy yui classes - ignore these&lt;br /&gt;
* &amp;lt;code&amp;gt;damyon-per-in-moodle-com--stable_master&amp;lt;/code&amp;gt; The current hostname for the site + the site name&lt;br /&gt;
* &amp;lt;code&amp;gt;pagelayout-course&amp;lt;/code&amp;gt; The layout type for the current page&lt;br /&gt;
* &amp;lt;code&amp;gt;course-11&amp;lt;/code&amp;gt; The id of the current course&lt;br /&gt;
* &amp;lt;code&amp;gt;context-497&amp;lt;/code&amp;gt; The current context id&lt;br /&gt;
* &amp;lt;code&amp;gt;category-1&amp;lt;/code&amp;gt; The category for the current course&lt;br /&gt;
* &amp;lt;code&amp;gt;drawer-open-left&amp;lt;/code&amp;gt; Added / removed when the navigation drawer is opened / closed in Boost&lt;br /&gt;
* &amp;lt;code&amp;gt;jsenabled&amp;lt;/code&amp;gt; True if the browser supports javascript&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/dev/Themes_overview#.3Cbody.3E_CSS_id_and_classes Read about Body id and classes].&lt;br /&gt;
&lt;br /&gt;
In our example the page layout is the most useful here as we have a specific page layout for login pages. We can now craft a rule that applies a background image only to login pages using &amp;quot;body.pagelayout-login&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== How do we refer to an image in SCSS ? ===&lt;br /&gt;
So now we can add a rule to the post.scss which will set the background image for the login page. First we need to know how to construct a url to the background images from our stylesheet. &lt;br /&gt;
&lt;br /&gt;
In stylesheets in Moodle we can use a special pix tag to refer to images from our theme. The rule to attach the background image looks like this:&lt;br /&gt;
&#039;&#039;scss/post.scss&#039;&#039;&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
body.pagelayout-login {                                                                                                             &lt;br /&gt;
    background-image: url([[pix:theme_photo|loginbackgroundimage]]);                                                                &lt;br /&gt;
    background-size: cover;                                                                                                         &lt;br /&gt;
}                          &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are 2 important parts to this tag (the bit in square brackets). The first is &amp;quot;theme_photo&amp;quot;. In this case we are passing a component name, the image serving code in theme_config::resolve_image_location() will then look for an image file in several locations. One of these is in &amp;quot;$CFG-&amp;gt;dataroot/pix_plugins/$type/$plugin/$image&amp;quot;. We can use this to make sure the image gets served correctly by copying the file saved in the setting to this location every time it is updated. (There is an alterative way we could do this by implementing pluginfile.php in our theme - which you can read about in the [[File API]] ).&lt;br /&gt;
&lt;br /&gt;
If we had just passed the value &amp;quot;theme&amp;quot; the image serving code would have looked for the image in the &amp;quot;pix&amp;quot; folder of our theme.&lt;br /&gt;
&lt;br /&gt;
So - we need this final change to copy the image file into our dataroot each time the setting is changed.&lt;br /&gt;
&lt;br /&gt;
In the settings file we will update the callback to a new function which we will define in our lib.php.&lt;br /&gt;
&#039;&#039;settings.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    // Login page background setting.                                                                                               &lt;br /&gt;
    // We use variables for readability.                                                                                            &lt;br /&gt;
    $name = &#039;theme_photo/loginbackgroundimage&#039;;                                                                                     &lt;br /&gt;
    $title = get_string(&#039;loginbackgroundimage&#039;, &#039;theme_photo&#039;);                                                                     &lt;br /&gt;
    $description = get_string(&#039;loginbackgroundimage_desc&#039;, &#039;theme_photo&#039;);                                                          &lt;br /&gt;
    // This creates the new setting.                                                                                                &lt;br /&gt;
    $setting = new admin_setting_configstoredfile($name, $title, $description, &#039;loginbackgroundimage&#039;);                             &lt;br /&gt;
    // This function will copy the image into the data_root location it can be served from.                                         &lt;br /&gt;
    $setting-&amp;gt;set_updatedcallback(&#039;theme_photo_update_settings_images&#039;);                                                            &lt;br /&gt;
    // We always have to add the setting to a page for it to have any effect.                                                       &lt;br /&gt;
    $page-&amp;gt;add($setting);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;lib.php&#039;&#039;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_photo_update_settings_images($settingname) {                                                                         &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // The setting name that was updated comes as a string like &#039;s_theme_photo_loginbackgroundimage&#039;.                               &lt;br /&gt;
    // We split it on &#039;_&#039; characters.                                                                                               &lt;br /&gt;
    $parts = explode(&#039;_&#039;, $settingname);                                                                                            &lt;br /&gt;
    // And get the last one to get the setting name..                                                                               &lt;br /&gt;
    $settingname = end($parts);                                                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Admin settings are stored in system context.                                                                                 &lt;br /&gt;
    $syscontext = context_system::instance();                                                                                       &lt;br /&gt;
    // This is the component name the setting is stored in.                                                                         &lt;br /&gt;
    $component = &#039;theme_photo&#039;;                                                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // This is the value of the admin setting which is the filename of the uploaded file.                                           &lt;br /&gt;
    $filename = get_config($component, $settingname);                                                                               &lt;br /&gt;
    // We extract the file extension because we want to preserve it.                                                                &lt;br /&gt;
    $extension = substr($filename, strrpos($filename, &#039;.&#039;) + 1);                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // This is the path in the moodle internal file system.                                                                         &lt;br /&gt;
    $fullpath = &amp;quot;/{$syscontext-&amp;gt;id}/{$component}/{$settingname}/0{$filename}&amp;quot;;                                                      &lt;br /&gt;
    // Get an instance of the moodle file storage.                                                                                  &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    // This is an efficient way to get a file if we know the exact path.                                                            &lt;br /&gt;
    if ($file = $fs-&amp;gt;get_file_by_hash(sha1($fullpath))) {                                                                           &lt;br /&gt;
        // We got the stored file - copy it to dataroot.                                                                            &lt;br /&gt;
        // This location matches the searched for location in theme_config::resolve_image_location.                                 &lt;br /&gt;
        $pathname = $CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039; . $settingname . &#039;.&#039; . $extension;                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // This pattern matches any previous files with maybe different file extensions.                                            &lt;br /&gt;
        $pathpattern = $CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039; . $settingname . &#039;.*&#039;;                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Make sure this dir exists.                                                                                               &lt;br /&gt;
        @mkdir($CFG-&amp;gt;dataroot . &#039;/pix_plugins/theme/photo/&#039;, $CFG-&amp;gt;directorypermissions, true);                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Delete any existing files for this setting.                                                                              &lt;br /&gt;
        foreach (glob($pathpattern) as $filename) {                                                                                 &lt;br /&gt;
            @unlink($filename);                                                                                                     &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Copy the current file to this location.                                                                                  &lt;br /&gt;
        $file-&amp;gt;copy_content_to($pathname);                                                                                          &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Reset theme caches.                                                                                                          &lt;br /&gt;
    theme_reset_all_caches();                                                                                                       &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
I won&#039;t show it here - but it is now easy to add a new background image setting for every layout type. I can re-use this theme_photo_update_settings_images callback for each one - so all I have to do is add the setting to the settings.php file, add the SCSS rule to the scss/post.scss file and add the lang strings to the language file.&lt;br /&gt;
&lt;br /&gt;
Thats 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>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Chat&amp;diff=55751</id>
		<title>Chat</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Chat&amp;diff=55751"/>
		<updated>2019-03-16T07:03:47Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle developer community members meet and discuss moodle development techniques and problems in an online Moodle Dev Chat. &lt;br /&gt;
&lt;br /&gt;
We use a public [https://telegram.me/moodledev Telegram room called moodledev]. &lt;br /&gt;
&lt;br /&gt;
Everybody is welcome to join, given the following policies are respected.&lt;br /&gt;
&lt;br /&gt;
Are you a student looking for [[GSOC| GSOC 2019]]?&lt;br /&gt;
&lt;br /&gt;
=== Moodle Dev Chat policies ===&lt;br /&gt;
&lt;br /&gt;
; Don&#039;t use the chat to get support for using Moodle: There are [https://moodle.org/course moodle.org forums] for that, or talk to a [http://moodle.com/partners Moodle Partner]&lt;br /&gt;
; Be nice: Help us maintain a great developer community: Be respectful to others&#039; viewpoints. Give and accept the constructive feedback and eventually criticism, too. Be honest, but not offensive.&lt;br /&gt;
; Speak English in the chat. : Moodle is a global project with worldwide community and English - even on elementary level - works best for us.&lt;br /&gt;
; Use your real name in the chat. : Keep it consistent with your moodle.org profile and Git commits.&lt;br /&gt;
; Keep topics and discussions focused. : Everything you post in the chat, hits several hundreds of other people instantly. Let us not disturb each other.&lt;br /&gt;
; Avoid funny animated gifs, memes and stickers. : There are better places online for sharing them.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Boost_Presets&amp;diff=55620</id>
		<title>Boost Presets</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Boost_Presets&amp;diff=55620"/>
		<updated>2019-03-03T05:50:22Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Themes}}&lt;br /&gt;
A preset is a scss file designed to be added to the &amp;quot;Boost&amp;quot; theme, or a child of it. It combines the bootstrap 4 SCSS files, with the required moodle SCSS files and adds a layer of customisation on top.&lt;br /&gt;
&lt;br /&gt;
Preset files can be uploaded in to the admin settings for the theme, and then chosen from a list of installed presets. They can be shared on the moodle.net site [http://moodle.net/boost Boost presets].&lt;br /&gt;
&lt;br /&gt;
== What is in a preset file? ==&lt;br /&gt;
&lt;br /&gt;
A preset file is just a SCSS file with 3 sections. We will call them &amp;quot;variables&amp;quot;, &amp;quot;import&amp;quot; and &amp;quot;rules&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
For Moodle 3.4 and earlier:&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// An example preset file.&lt;br /&gt;
&lt;br /&gt;
/*************************** Variables section. *****************************/&lt;br /&gt;
// Create variables to override the default value for variables used in the Moodle and Bootstrap SCSS files.&lt;br /&gt;
&lt;br /&gt;
$card-bg: green;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/*************************** Import section  *****************************/&lt;br /&gt;
// Always the same.&lt;br /&gt;
@import &amp;quot;moodle&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
/*************************** Rules section ****************************/&lt;br /&gt;
body {&lt;br /&gt;
    background-color: $card-bg;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
From Moodle 3.5 and on:&lt;br /&gt;
&amp;lt;code scss&amp;gt;&lt;br /&gt;
// An example preset file.&lt;br /&gt;
&lt;br /&gt;
/*************************** Variables section. *****************************/&lt;br /&gt;
// Create variables to override the default value for variables used in the Moodle and Bootstrap SCSS files.&lt;br /&gt;
&lt;br /&gt;
$card-bg: green;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
/*************************** Import section  *****************************/&lt;br /&gt;
@import &amp;quot;fontawesome&amp;quot;;&lt;br /&gt;
@import &amp;quot;bootstrap&amp;quot;;&lt;br /&gt;
@import &amp;quot;moodle&amp;quot;;&lt;br /&gt;
&lt;br /&gt;
/*************************** Rules section ****************************/&lt;br /&gt;
body {&lt;br /&gt;
    background-color: $card-bg;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first section is where you define default values for variables used by the standard Moodle and Bootstrap SCSS files. Because of the way SCSS variables, defining them first will allow variables used later on to be overwritten, but not defining them means they will use their default values. A good starting point when looking for variables to customise is here: [https://github.com/moodle/moodle/blob/master/theme/boost/scss/bootstrap/_variables.scss Bootstrap variables].&lt;br /&gt;
&lt;br /&gt;
The import section is where we import all the font awesome, moodle and bootstrap standard SCSS files. &lt;br /&gt;
&lt;br /&gt;
The last section is where we add our custom styles. We do it last so they have precedence over any rules that were defined earlier with the same specificity.&lt;br /&gt;
&lt;br /&gt;
== Bootswatches ==&lt;br /&gt;
&lt;br /&gt;
These presets are very similar to [https://bootswatch.com/ Bootswatch] files. In fact you can build a preset file from a Bootswatch file by using the cli script shipped with the Boost theme. See https://github.com/moodle/moodle/tree/master/theme/boost/cli for the script and instructions.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Chat&amp;diff=54793</id>
		<title>Chat</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Chat&amp;diff=54793"/>
		<updated>2018-09-23T22:23:46Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle developer community members meet and discuss moodle development techniques and problems in an online Moodle Dev Chat. &lt;br /&gt;
&lt;br /&gt;
We use a public [https://telegram.me/moodledev Telegram room called moodledev]. &lt;br /&gt;
&lt;br /&gt;
Everybody is welcome to join, given the following policies are respected.&lt;br /&gt;
&lt;br /&gt;
=== Moodle Dev Chat policies ===&lt;br /&gt;
&lt;br /&gt;
; Don&#039;t use the chat to get support for using Moodle: There are [https://moodle.org/course moodle.org forums] for that, or talk to a [http://moodle.com/partners Moodle Partner]&lt;br /&gt;
; Be nice: Help us maintain a great developer community: Be respectful to others&#039; viewpoints. Give and accept the constructive feedback and eventually criticism, too. Be honest, but not offensive.&lt;br /&gt;
; Speak English in the chat. : Moodle is a global project with worldwide community and English - even on elementary level - works best for us.&lt;br /&gt;
; Use your real name in the chat. : Keep it consistent with your moodle.org profile and Git commits.&lt;br /&gt;
; Keep topics and discussions focused. : Everything you post in the chat, hits several hundreds of other people instantly. Let us not disturb each other.&lt;br /&gt;
; Avoid funny animated gifs, memes and stickers. : There are better places online for sharing them.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Chat&amp;diff=54792</id>
		<title>Chat</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Chat&amp;diff=54792"/>
		<updated>2018-09-23T22:22:50Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle developer community members meet and discuss moodle development techniques and problems in an online Moodle Dev Chat. &lt;br /&gt;
&lt;br /&gt;
We use a public [https://telegram.me/moodledev Telegram room called moodledev]. &lt;br /&gt;
&lt;br /&gt;
Everybody is welcome to join, given the following policies are respected.&lt;br /&gt;
&lt;br /&gt;
=== Moodle Dev Chat policies ===&lt;br /&gt;
&lt;br /&gt;
; Don&#039;t use the chat to get support for using Moodle: There are [moodle.org forums|https://moodle.org/course] for that, or talk to a [Moodle Partner|http://moodle.com/partners]&lt;br /&gt;
; Be nice: Help us maintain a great developer community: Be respectful to others&#039; viewpoints. Give and accept the constructive feedback and eventually criticism, too. Be honest, but not offensive.&lt;br /&gt;
; Speak English in the chat. : Moodle is a global project with worldwide community and English - even on elementary level - works best for us.&lt;br /&gt;
; Use your real name in the chat. : Keep it consistent with your moodle.org profile and Git commits.&lt;br /&gt;
; Keep topics and discussions focused. : Everything you post in the chat, hits several hundreds of other people instantly. Let us not disturb each other.&lt;br /&gt;
; Avoid funny animated gifs, memes and stickers. : There are better places online for sharing them.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Main_Page&amp;diff=54554</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Main_Page&amp;diff=54554"/>
		<updated>2018-08-01T01:34:52Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Changed protection level for &amp;quot;Main Page&amp;quot;: Andrew wanted to edit some ([Move=Allow only administrators] (indefinite))&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#addbodyclass:moodledocs-mainpage}}&lt;br /&gt;
{{#addbodyclass:moodledocs-logo}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;navtrail&amp;quot;&amp;gt;[https://docs.moodle.org/overview/ Docs overview] ► [[{{PAGENAME}}|Dev docs]]&amp;lt;/div&amp;gt;&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&amp;lt;div class=&amp;quot;container-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Welcome to the Developer Documentation.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These Developer Docs are for developers who work with Moodle code, plugins and themes, or [[Contributing to Moodle|contribute to the Moodle project]] in other ways, such as [[Translation|translation]].&lt;br /&gt;
&lt;br /&gt;
If you manage a Moodle site, or if you teach using Moodle, try the [[:en:Main_page|User docs]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;row-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Overview]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Mission]]&lt;br /&gt;
* [[Roadmap]]&lt;br /&gt;
* [[Releases]]&lt;br /&gt;
* [[Process|Development processes]]&lt;br /&gt;
* [[Developer meetings]]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=55 Forum discussions]&lt;br /&gt;
* [https://telegram.me/moodledev Telegram Moodle Dev Chat room]&lt;br /&gt;
* [http://moodle.org/dev Developer credits/statistics]&lt;br /&gt;
* [[Moodle_research|Research]]&lt;br /&gt;
* [[Testing]]&lt;br /&gt;
[[Overview|More overview info ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Plugins|Plugin development]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Activity modules]]&lt;br /&gt;
* [[Blocks]]&lt;br /&gt;
* [[Themes]]&lt;br /&gt;
* [[Course formats]]&lt;br /&gt;
* [[Enrolment plugins]]&lt;br /&gt;
* [[Authentication plugins]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Filters]]&lt;br /&gt;
[[Plugins|Full list of plugin types ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Core APIs]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
* [[Exporter|Exporter API]]&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[Migrating logging calls in plugins|Logging]]&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
* [[Persistent|Persistent API]]&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[String API]] &lt;br /&gt;
* [[Web service API functions]]&lt;br /&gt;
[[Core APIs|Full list of core APIs ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;Guidelines&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Coding|Coding guidelines]]&lt;br /&gt;
* [[Git_for_developers|Git use]]&lt;br /&gt;
* [[Plugin contribution|Contributing plugins]]&lt;br /&gt;
* [[How_to_create_a_patch|Creating patches]]&lt;br /&gt;
* [[PHPUnit|PHPUnit tests]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Writing tests]]&lt;br /&gt;
* [[Aria Guidelines]]&lt;br /&gt;
* [[HTML Guidelines]]&lt;br /&gt;
* [[Automatic class loading]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[AJAX]]&lt;br /&gt;
* [[Communication Between Components]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[:Category:Developer tools|Developer tools]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Linting]]&lt;br /&gt;
* [[Setting up Eclipse]]&lt;br /&gt;
* [[Setting up Netbeans]]&lt;br /&gt;
* [[:Category:Firefox extensions|Firefox extensions]]&lt;br /&gt;
[[:Category:Developer tools|Full list of developer tools ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Moodle Mobile]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
*[[Moodle Mobile Customization]]&lt;br /&gt;
*[[Mobile support for plugins]]&lt;br /&gt;
*[[Moodle Mobile Themes]]&lt;br /&gt;
*[[Moodle Mobile FAQ]]&lt;br /&gt;
[[:Category:Mobile|Full list of mobile app documentation ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Martin_Dougiamas&amp;diff=54553</id>
		<title>User:Martin Dougiamas</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Martin_Dougiamas&amp;diff=54553"/>
		<updated>2018-08-01T01:33:11Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;It is me.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meetings&amp;diff=54386</id>
		<title>Developer meetings</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meetings&amp;diff=54386"/>
		<updated>2018-06-14T07:13:46Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Meeting notes ==&lt;br /&gt;
&lt;br /&gt;
This page keeps track of all Moodle DevJams, online meetings and other developer-focussed events around the world. &lt;br /&gt;
&lt;br /&gt;
* 2018&lt;br /&gt;
** [[Glasgow DevJam March 2018]]&lt;br /&gt;
** [[Barcelona DevJam June 2018]]&lt;br /&gt;
** [[Developer meeting July 2018]]&lt;br /&gt;
&lt;br /&gt;
* 2017 &lt;br /&gt;
** [https://devpad.moodle.org/p/mootus17 Miami DevJam November 2017]&lt;br /&gt;
** [[Mannheim DevJam June 2017]]&lt;br /&gt;
** [[London hackfest April 2017]]&lt;br /&gt;
&lt;br /&gt;
* 2016&lt;br /&gt;
** [[Developer meeting September 2016|September 2016 meeting]]&lt;br /&gt;
** [[Developer meeting May 2016|May 2016 meeting]]&lt;br /&gt;
** [[Developer meeting February 2016|February 2016 meeting]] &lt;br /&gt;
** [[London hackfest March 2016]]&lt;br /&gt;
&lt;br /&gt;
* 2015&lt;br /&gt;
** [[Developer meeting October 2015|October 2015 meeting]]&lt;br /&gt;
** [[Minneapolis hackfest August 2015]]&lt;br /&gt;
** [[Developer meeting July 2015|July 2015 meeting]]&lt;br /&gt;
** [[Melbourne hackfest July 2015]]&lt;br /&gt;
** [[Dublin hackfest May 2015]]&lt;br /&gt;
** [[Developer meeting April 2015|April 2015 meeting]]&lt;br /&gt;
** [[Developer meeting January 2015|January 2015 meeting]]&lt;br /&gt;
&lt;br /&gt;
* 2014&lt;br /&gt;
** [[Developer meeting October 2014|October 2014 meeting]]&lt;br /&gt;
** [[Developer meeting July 2014|July 2014 meeting]]&lt;br /&gt;
** [[Developer meeting April 2014|April 2014 meeting]]&lt;br /&gt;
** [[Hackfest UK 2014]]&lt;br /&gt;
** [[Developer meeting January 2014|January 2014 meeting]]&lt;br /&gt;
&lt;br /&gt;
* 2013&lt;br /&gt;
** [[Developer meeting October 2013|October 2013 meeting]]&lt;br /&gt;
** [[Developer meeting July 2013|July 2013 meeting]]&lt;br /&gt;
** [[Developer meeting April 2013|April 2013 meeting]]&lt;br /&gt;
** [[Developer meeting February 2013|February 2013 meeting]]&lt;br /&gt;
&lt;br /&gt;
* 2012&lt;br /&gt;
** [[Developer meeting November 2012|November 2012 meeting]]&lt;br /&gt;
** [[Perth Hackfest October 2012]]&lt;br /&gt;
** [[Developer meeting August 2012|August 2012 meeting]]&lt;br /&gt;
** [[Developer meeting May 2012|May 2012 meeting]]&lt;br /&gt;
** [[Developer meeting February 2012|February 2012 meeting]]&lt;br /&gt;
** [https://docs.google.com/document/d/1inDtTN5MyCs-o1CGmZoRxSo-n1KsIKExQQaUN4kw9Zo/edit Belgium 2012 hackfest]&lt;br /&gt;
&lt;br /&gt;
* 2011&lt;br /&gt;
** [[Developer meeting November 2011|November 2011 meeting notes]]&lt;br /&gt;
** [[Developer meeting August 2011|August 2011 meeting notes]]&lt;br /&gt;
** [[Developer meeting May 2011|May 2011 meeting notes]]&lt;br /&gt;
* 2010&lt;br /&gt;
** [[Developer meeting November 2010|November 2010 meeting notes]]&lt;br /&gt;
** [[Developer meeting May 2010|May 2010 meeting notes]]&lt;br /&gt;
* 2009&lt;br /&gt;
** [[Czech Hackfest 2009 notes]]&lt;br /&gt;
** [[Developer meeting September 2009|September 2009 meeting notes]]&lt;br /&gt;
** [[Developer meeting April 2009|April 2009 meeting notes]]&lt;br /&gt;
** [[Developer meeting January 2009|January 2009 meeting notes]]&lt;br /&gt;
* 2008&lt;br /&gt;
** [[Developer meeting November 2008|November 2008 meeting notes]]&lt;br /&gt;
** [[Developer meeting September 2008|September 2008 meeting notes]]&lt;br /&gt;
** [[SF Developer HackFest|San Francisco 2008 Developer HackFest]]&lt;br /&gt;
** [[Developer meeting April 2008|April 2008 meeting notes]]&lt;br /&gt;
** [[Developer meeting February 2008|February 2008 meeting notes]]&lt;br /&gt;
* 2007&lt;br /&gt;
** [[MoodleMoot 2007 HackFest|UK 2007 MoodleMoot HackFest]]&lt;br /&gt;
** [[Developer conference April 2007|April 2007 meeting notes]]&lt;br /&gt;
* 2006&lt;br /&gt;
** [[Developer conference December 2006|December 2006 meeting notes]]&lt;br /&gt;
** [[Developer conference May 2006|May 2006 meeting notes]]&lt;br /&gt;
** [[Developer conference February 2006|February 2006 meeting notes]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=53594</id>
		<title>MoodleNet</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet&amp;diff=53594"/>
		<updated>2018-01-11T08:15:46Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* Misc. */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[File:Moodlenet-logo.png|400px]]&lt;br /&gt;
&lt;br /&gt;
Short URL: &#039;&#039;&#039;https://moodle.com/moodlenet&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note: This page describes a new project started in 2017. For the legacy mechanism of inter-connecting multiple Moodle and Mahara sites into a network, please see the [https://docs.moodle.org/en/MNet MNet] page.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;background-color:#F87F16; padding:10px; text-align:center; color:#fff; font-size:1.2em;&amp;quot;&amp;gt;Check out the draft [https://docs.moodle.org/dev/MoodleNet_whitepaper Project MoodleNet whitepaper]&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== What is MoodleNet? ==&lt;br /&gt;
&lt;br /&gt;
[[File:moodlenet-core-features.png|thumb|MoodleNet core features (click to enlarge)]]&lt;br /&gt;
&lt;br /&gt;
[[File:1600px-moodlenet-ecosystem.png|thumb|MoodleNet as part of the wider Moodle ecosystem (click to enlarge)]]&lt;br /&gt;
&lt;br /&gt;
Project MoodleNet is currently described by Martin Dougiamas, CEO of Moodle as, &#039;&#039;&#039;&amp;quot;a new open social media platform for educators, focussed on professional development and open content&amp;quot;&#039;&#039;&#039;. MoodleNet will be an integral part of the Moodle ecosystem. We&#039;ll be building out this page as the project develops.&lt;br /&gt;
&lt;br /&gt;
It is envisaged that MoodleNet will contain features such as the following, listed in suggested order of development:&lt;br /&gt;
&lt;br /&gt;
* Identity and reputation&lt;br /&gt;
* Messaging&lt;br /&gt;
* Activity feed&lt;br /&gt;
* Access to openly-licensed resources&lt;br /&gt;
* Crowdfunding&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
See [https://goo.gl/xJBgQs this short slide deck]. It will be built according to the following principles:&lt;br /&gt;
&lt;br /&gt;
* Open&lt;br /&gt;
* Safe&lt;br /&gt;
* Private&lt;br /&gt;
* Ethical&lt;br /&gt;
* Transparent&lt;br /&gt;
* Connected&lt;br /&gt;
&lt;br /&gt;
== Updates ==&lt;br /&gt;
&lt;br /&gt;
* [https://blog.moodle.net/ Blog]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?f=1243 Discussion forum]&lt;br /&gt;
* [https://t.me/project_moodlenet Telegram channel]&lt;br /&gt;
* [https://trello.com/b/0KCE6858/project-moodlenet Trello board]&lt;br /&gt;
* [https://tracker.moodle.org/secure/RapidBoard.jspa?rapidView=81&amp;amp;projectKey=MDLNET Issue tracker]&lt;br /&gt;
&lt;br /&gt;
== Feedback ==&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-meetings Notes from meetings]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-MootUS17  Miami MoodleMoot sessions (Nov 2017)]&lt;br /&gt;
&lt;br /&gt;
== Misc. ==&lt;br /&gt;
&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet_whitepaper Project MoodleNet Whitepaper]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet/Decision_Log Decision log]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-research Research]&lt;br /&gt;
* [https://docs.moodle.org/dev/MoodleNet-metaphors Explaining MoodleNet]&lt;br /&gt;
&lt;br /&gt;
[[es:MoodleNet]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meetings&amp;diff=53418</id>
		<title>Developer meetings</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meetings&amp;diff=53418"/>
		<updated>2017-11-22T03:50:45Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* Meeting notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Meeting notes ==&lt;br /&gt;
&lt;br /&gt;
* 2017 &lt;br /&gt;
** [https://devpad.moodle.org/p/mootus17 Miami DevJam November 2017]&lt;br /&gt;
** [[Mannheim DevJam June 2017]]&lt;br /&gt;
** [[London hackfest April 2017]]&lt;br /&gt;
&lt;br /&gt;
* 2016&lt;br /&gt;
** [[Developer meeting September 2016|September 2016 meeting]]&lt;br /&gt;
** [[Developer meeting May 2016|May 2016 meeting]]&lt;br /&gt;
** [[Developer meeting February 2016|February 2016 meeting]] &lt;br /&gt;
** [[London hackfest March 2016]]&lt;br /&gt;
&lt;br /&gt;
* 2015&lt;br /&gt;
** [[Developer meeting October 2015|October 2015 meeting]]&lt;br /&gt;
** [[Minneapolis hackfest August 2015]]&lt;br /&gt;
** [[Developer meeting July 2015|July 2015 meeting]]&lt;br /&gt;
** [[Melbourne hackfest July 2015]]&lt;br /&gt;
** [[Dublin hackfest May 2015]]&lt;br /&gt;
** [[Developer meeting April 2015|April 2015 meeting]]&lt;br /&gt;
** [[Developer meeting January 2015|January 2015 meeting]]&lt;br /&gt;
&lt;br /&gt;
* 2014&lt;br /&gt;
** [[Developer meeting October 2014|October 2014 meeting]]&lt;br /&gt;
** [[Developer meeting July 2014|July 2014 meeting]]&lt;br /&gt;
** [[Developer meeting April 2014|April 2014 meeting]]&lt;br /&gt;
** [[Hackfest UK 2014]]&lt;br /&gt;
** [[Developer meeting January 2014|January 2014 meeting]]&lt;br /&gt;
&lt;br /&gt;
* 2013&lt;br /&gt;
** [[Developer meeting October 2013|October 2013 meeting]]&lt;br /&gt;
** [[Developer meeting July 2013|July 2013 meeting]]&lt;br /&gt;
** [[Developer meeting April 2013|April 2013 meeting]]&lt;br /&gt;
** [[Developer meeting February 2013|February 2013 meeting]]&lt;br /&gt;
&lt;br /&gt;
* 2012&lt;br /&gt;
** [[Developer meeting November 2012|November 2012 meeting]]&lt;br /&gt;
** [[Perth Hackfest October 2012]]&lt;br /&gt;
** [[Developer meeting August 2012|August 2012 meeting]]&lt;br /&gt;
** [[Developer meeting May 2012|May 2012 meeting]]&lt;br /&gt;
** [[Developer meeting February 2012|February 2012 meeting]]&lt;br /&gt;
** [https://docs.google.com/document/d/1inDtTN5MyCs-o1CGmZoRxSo-n1KsIKExQQaUN4kw9Zo/edit Belgium 2012 hackfest]&lt;br /&gt;
&lt;br /&gt;
* 2011&lt;br /&gt;
** [[Developer meeting November 2011|November 2011 meeting notes]]&lt;br /&gt;
** [[Developer meeting August 2011|August 2011 meeting notes]]&lt;br /&gt;
** [[Developer meeting May 2011|May 2011 meeting notes]]&lt;br /&gt;
* 2010&lt;br /&gt;
** [[Developer meeting November 2010|November 2010 meeting notes]]&lt;br /&gt;
** [[Developer meeting May 2010|May 2010 meeting notes]]&lt;br /&gt;
* 2009&lt;br /&gt;
** [[Czech Hackfest 2009 notes]]&lt;br /&gt;
** [[Developer meeting September 2009|September 2009 meeting notes]]&lt;br /&gt;
** [[Developer meeting April 2009|April 2009 meeting notes]]&lt;br /&gt;
** [[Developer meeting January 2009|January 2009 meeting notes]]&lt;br /&gt;
* 2008&lt;br /&gt;
** [[Developer meeting November 2008|November 2008 meeting notes]]&lt;br /&gt;
** [[Developer meeting September 2008|September 2008 meeting notes]]&lt;br /&gt;
** [[SF Developer HackFest|San Francisco 2008 Developer HackFest]]&lt;br /&gt;
** [[Developer meeting April 2008|April 2008 meeting notes]]&lt;br /&gt;
** [[Developer meeting February 2008|February 2008 meeting notes]]&lt;br /&gt;
* 2007&lt;br /&gt;
** [[MoodleMoot 2007 HackFest|UK 2007 MoodleMoot HackFest]]&lt;br /&gt;
** [[Developer conference April 2007|April 2007 meeting notes]]&lt;br /&gt;
* 2006&lt;br /&gt;
** [[Developer conference December 2006|December 2006 meeting notes]]&lt;br /&gt;
** [[Developer conference May 2006|May 2006 meeting notes]]&lt;br /&gt;
** [[Developer conference February 2006|February 2006 meeting notes]]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
*[[Roadmap]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=MoodleNet-metaphors&amp;diff=53382</id>
		<title>MoodleNet-metaphors</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=MoodleNet-metaphors&amp;diff=53382"/>
		<updated>2017-11-21T08:45:05Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;&amp;lt; [https://docs.moodle.org/dev/MoodleNet Back to MoodleNet index]&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
Introducing new concepts to people can be difficult, as we all understand the future through the lens of past experience. Therefore, as imperfect as these analogies are, they all get at &#039;&#039;something&#039;&#039; which will help MoodleNet empower educators and further Moodle&#039;s mission:&lt;br /&gt;
&lt;br /&gt;
* [https://jetpack.com/ Jetpack for WordPress] - a plugin for WordPress created by the developers of WordPress. This allows self-hosted installations to be connected to a wordpress.com account to enable extra features. Good for the user (free additional functionality), and good for Automattic, who make Worpress (track number of installations, potential to upsell products/services)&lt;br /&gt;
* [https://en.wikipedia.org/wiki/Office_Assistant Office Assistant] - although widely parodied / derided, &#039;Clippy&#039; (as it became known) provided an early form of just-in-time help for for those using Microsoft Office. An updated version of this, with natural-language search and contextual information would be an intelligent assistant and very useful &#039;&#039;within&#039;&#039; Moodle installations.&lt;br /&gt;
* [https://getsatisfaction.com Get Satisfaction] - a customer community that can be embedded within the product or service being used by a customer. It is customised to fit in seamlessly with the brand, and allows users to interact with support and community discussions without having to go to a separate &#039;place&#039;.&lt;br /&gt;
* LinkedIN with kickstarter built-in, connected to all Moodle sites.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Mission&amp;diff=52745</id>
		<title>Mission</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Mission&amp;diff=52745"/>
		<updated>2017-07-20T04:00:17Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Our Mission==&lt;br /&gt;
&lt;br /&gt;
The mission of the Moodle project (including Moodle HQ and all Moodle software) is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Empowering educators to improve our world.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Our Vision==&lt;br /&gt;
&lt;br /&gt;
Our goals for the future are simple:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;To give the world the most effective platform for learning.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Our Values==&lt;br /&gt;
&lt;br /&gt;
These are the values that we encourage each other to uphold, for the good of the educators we serve and each other:&lt;br /&gt;
&lt;br /&gt;
;Education&lt;br /&gt;
:Education is the foundation of making the world a better place. We, our teachers and our students all need to be always learning, and looking for ways to improve how we learn.&lt;br /&gt;
&lt;br /&gt;
;Respect&lt;br /&gt;
:We treat everyone with respect and sensitivity, recognising the importance of their contributions: team members, customers, partners, suppliers and competitors.&lt;br /&gt;
&lt;br /&gt;
;Integrity&lt;br /&gt;
:We employ the highest ethical standards, demonstrating honesty and fairness in every action that we take.&lt;br /&gt;
&lt;br /&gt;
;Openness&lt;br /&gt;
:Our goals, our tools, our processes and our results shall be open as much as is practical. Our team members are encouraged to speak openly and communicate freely both internally and externally.&lt;br /&gt;
&lt;br /&gt;
;Innovation&lt;br /&gt;
:We encourage a culture of experimentation and research, where entrepreneurship and prudent risk-taking are encouraged, rewarded and incorporated.&lt;br /&gt;
&lt;br /&gt;
[[es:dev/Misión]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Main_Page&amp;diff=52730</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Main_Page&amp;diff=52730"/>
		<updated>2017-07-18T06:03:54Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#addbodyclass:moodledocs-mainpage}}&lt;br /&gt;
{{#addbodyclass:moodledocs-logo}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;navtrail&amp;quot;&amp;gt;[https://docs.moodle.org/overview/ Docs overview] ► [[{{PAGENAME}}|Dev docs]]&amp;lt;/div&amp;gt;&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&amp;lt;div class=&amp;quot;container-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Welcome to the Developer Documentation.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These Developer Docs are for developers who work with Moodle code, plugins and themes, or [[Contributing to Moodle|contribute to the Moodle project]] in other ways, such as [[Translation|translation]].&lt;br /&gt;
&lt;br /&gt;
If you manage a Moodle site, or if you teach using Moodle, try the [[:en:Main_page|User docs]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;row-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Overview]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Mission]]&lt;br /&gt;
* [[Roadmap]]&lt;br /&gt;
* [[Releases]]&lt;br /&gt;
* [[Process|Development processes]]&lt;br /&gt;
* [[Developer meetings]]&lt;br /&gt;
* [[Working Groups]]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=55 Forum discussions]&lt;br /&gt;
* [http://moodle.org/dev Developer credits/statistics]&lt;br /&gt;
* [[Moodle_research|Research]]&lt;br /&gt;
* [[Testing]]&lt;br /&gt;
[[Overview|More overview info ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Plugins|Plugin development]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Activity modules]]&lt;br /&gt;
* [[Blocks]]&lt;br /&gt;
* [[Themes]]&lt;br /&gt;
* [[Course formats]]&lt;br /&gt;
* [[Enrolment plugins]]&lt;br /&gt;
* [[Authentication plugins]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Filters]]&lt;br /&gt;
[[Plugins|Full list of plugin types ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Core APIs]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
* [[Exporter|Exporter API]]&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[Migrating logging calls in plugins|Logging]]&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
* [[Persistent|Persistent API]]&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[String API]] &lt;br /&gt;
* [[Web service API functions]]&lt;br /&gt;
[[Core APIs|Full list of core APIs ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Guidelines]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Coding|Coding guidelines]]&lt;br /&gt;
* [[Git_for_developers|Git use]]&lt;br /&gt;
* [[Plugin contribution|Contributing plugins]]&lt;br /&gt;
* [[How_to_create_a_patch|Creating patches]]&lt;br /&gt;
* [[PHPUnit|PHPUnit tests]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Writing tests]]&lt;br /&gt;
* [[Aria Guidelines]]&lt;br /&gt;
* [[HTML Guidelines]]&lt;br /&gt;
* [[Automatic class loading]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[AJAX]]&lt;br /&gt;
* [[Communication Between Components]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[:Category:Developer tools|Developer tools]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Linting]]&lt;br /&gt;
* [[Setting up Eclipse]]&lt;br /&gt;
* [[Setting up Netbeans]]&lt;br /&gt;
* [[:Category:Firefox extensions|Firefox extensions]]&lt;br /&gt;
[[:Category:Developer tools|Full list of developer tools ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Moodle Mobile]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
*[[Moodle Mobile Customization]]&lt;br /&gt;
*[[Moodle Mobile Plugins Development]]&lt;br /&gt;
*[[Moodle Mobile Themes]]&lt;br /&gt;
*[[Moodle Mobile Developing a plugin tutorial]]&lt;br /&gt;
[[:Category:Mobile|Full list of mobile app documentation ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Main_Page&amp;diff=52729</id>
		<title>Main Page</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Main_Page&amp;diff=52729"/>
		<updated>2017-07-18T06:03:33Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#addbodyclass:moodledocs-mainpage}}&lt;br /&gt;
{{#addbodyclass:moodledocs-logo}}&lt;br /&gt;
&amp;lt;div class=&amp;quot;navtrail&amp;quot;&amp;gt;[https://docs.moodle.org/overview/ Docs overview] ► [[{{PAGENAME}}|Dev docs]]&amp;lt;/div&amp;gt;&lt;br /&gt;
__NOTOC__&lt;br /&gt;
&amp;lt;div class=&amp;quot;container-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Welcome to the Developer Documentation.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These Developer Docs are for developers who work with Moodle code, plugins and themes, or [[Contributing to Moodle|contribute to the Moodle project]] in other ways, such as [[Translation|translation]].&lt;br /&gt;
&lt;br /&gt;
If you manage a Moodle site, or if you teach using Moodle, try the [[:en:Main_page|User docs]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;row-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Overview]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Mission]]&lt;br /&gt;
* [[Roadmap]]&lt;br /&gt;
* [[Releases]]&lt;br /&gt;
* [[Process|Development processes]]&lt;br /&gt;
* [[Developer meetings]]&lt;br /&gt;
* [[Working Groups]]&lt;br /&gt;
* [https://moodle.org/mod/forum/view.php?id=55 Forum discussions]&lt;br /&gt;
* [http://moodle.org/dev Developer credits/statistics]&lt;br /&gt;
* [[Moodle_research|Research]]&lt;br /&gt;
* [[Testing]]&lt;br /&gt;
[[Overview|More overview info ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Plugins|Plugin development]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Activity modules]]&lt;br /&gt;
* [[Blocks]]&lt;br /&gt;
* [[Themes]]&lt;br /&gt;
* [[Course formats]]&lt;br /&gt;
* [[Enrolment plugins]]&lt;br /&gt;
* [[Authentication plugins]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Filters]]&lt;br /&gt;
[[Plugins|Full list of plugin types ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Core APIs]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Data manipulation API]]&lt;br /&gt;
* [[Exporter|Exporter API]]&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Form API]]&lt;br /&gt;
* [[Migrating logging calls in plugins|Logging]]&lt;br /&gt;
* [[Navigation API]]&lt;br /&gt;
* [[Page API]]&lt;br /&gt;
* [[Persistent|Persistent API]]&lt;br /&gt;
* [[Output API]]&lt;br /&gt;
* [[String API]] &lt;br /&gt;
* [[Web_service_API_functions]]&lt;br /&gt;
[[Core APIs|Full list of core APIs ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;row-fluid&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Guidelines]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Coding|Coding guidelines]]&lt;br /&gt;
* [[Git_for_developers|Git use]]&lt;br /&gt;
* [[Plugin contribution|Contributing plugins]]&lt;br /&gt;
* [[How_to_create_a_patch|Creating patches]]&lt;br /&gt;
* [[PHPUnit|PHPUnit tests]]&lt;br /&gt;
* [[Acceptance testing]]&lt;br /&gt;
* [[Writing tests]]&lt;br /&gt;
* [[Aria Guidelines]]&lt;br /&gt;
* [[HTML Guidelines]]&lt;br /&gt;
* [[Automatic class loading]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[AJAX]]&lt;br /&gt;
* [[Communication Between Components]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[:Category:Developer tools|Developer tools]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
* [[Linting]]&lt;br /&gt;
* [[Setting up Eclipse]]&lt;br /&gt;
* [[Setting up Netbeans]]&lt;br /&gt;
* [[:Category:Firefox extensions|Firefox extensions]]&lt;br /&gt;
[[:Category:Developer tools|Full list of developer tools ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;span4&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;h2&amp;gt;[[Moodle Mobile]]&amp;lt;/h2&amp;gt;&lt;br /&gt;
*[[Moodle Mobile Customization]]&lt;br /&gt;
*[[Moodle Mobile Plugins Development]]&lt;br /&gt;
*[[Moodle Mobile Themes]]&lt;br /&gt;
*[[Moodle Mobile Developing a plugin tutorial]]&lt;br /&gt;
[[:Category:Mobile|Full list of mobile app documentation ...]]&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.2_release_notes&amp;diff=51032</id>
		<title>Moodle 3.2 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.2_release_notes&amp;diff=51032"/>
		<updated>2016-11-08T03:25:56Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: Created page with &amp;quot;Coming soon.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Coming soon.&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Theme_And_Navigation_Project_3.2&amp;diff=50602</id>
		<title>Theme And Navigation Project 3.2</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Theme_And_Navigation_Project_3.2&amp;diff=50602"/>
		<updated>2016-07-07T20:33:12Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Theme And Navigation Project 3.2&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55070&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=335638&lt;br /&gt;
|assignee = [[User:Damyon Wiese]]&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
This page is dedicated to a set of changes for 3.2 all relating to the theme, and navigation in Moodle. &lt;br /&gt;
&lt;br /&gt;
The requirements for the new theme are:&lt;br /&gt;
* use a CSS framework that will be supported upstream for a long time&lt;br /&gt;
* testing framework needs to be theme independent&lt;br /&gt;
* simplify the navigation and make it more suitable for touch screens&lt;br /&gt;
* introduce quick navigation from course to course or section to section&lt;br /&gt;
* promote the content of each page rather than the peripheral sections (blocks)&lt;br /&gt;
* the default visual design of Moodle should look distinct from older versions&lt;br /&gt;
* every page with settings should use a consistent, recognisable UI element to get to the settings&lt;br /&gt;
* add lots of settings to the new theme so it can be used for many sites without installing a child-theme&lt;br /&gt;
* don&#039;t break existing themes or require changes from plugin developers&lt;br /&gt;
&lt;br /&gt;
More details about each requirement follow:&lt;br /&gt;
&lt;br /&gt;
= Use a CSS framework that will be supported upstream for a long time =&lt;br /&gt;
* Users affected: theme designers&lt;br /&gt;
* The problem: bootstrap 2 is unsupported&lt;br /&gt;
* The proposed solution: create a new theme based on Bootstrap 4&lt;br /&gt;
* Criteria for success: New moodle theme using a supported CSS framework with long term support that includes features for RTL and Accessibility and is popular with theme designers, the new theme should show proper styling for all pages&lt;br /&gt;
* MDL-55071&lt;br /&gt;
&lt;br /&gt;
= Testing framework needs to be theme independent =&lt;br /&gt;
* Users affected: developers&lt;br /&gt;
* The problem: feature files are written assuming the theme will be “clean”&lt;br /&gt;
* The proposed solution: Theme specific steps need to be identified and the theme should form part of the behat context. Different step implementations should be available for different themes&lt;br /&gt;
* Criteria for success: You should be able to specify which theme to run behat with and all tests should pass&lt;br /&gt;
* MDL-55072&lt;br /&gt;
&lt;br /&gt;
= Navigation is not intuitive or suitable on touch screens =&lt;br /&gt;
* Users affected: new moodle users, experienced moodle users&lt;br /&gt;
* The problem: navigation is a complex tree with inconsistent structure&lt;br /&gt;
* The proposed solution: Only show the path to the current node in the navigation, and it’s siblings as a flat list.&lt;br /&gt;
* Criteria for success: It is easier to determine your location in the navigation tree, it is easier to find pages related to the current page&lt;br /&gt;
* MDL-55073&lt;br /&gt;
&lt;br /&gt;
= Intuitively navigate from course to course or section to section =&lt;br /&gt;
* Users affected: new moodle users, experienced moodle users&lt;br /&gt;
* The problem: If the navigation tree is flattened, it is not possible to change between courses without leaving the course and entering a new one&lt;br /&gt;
* The proposed solution: Show a drop down menu for each item in the navbar&lt;br /&gt;
* Criteria for success: It is intuitive to quickly jump between courses and sections using the navbar&lt;br /&gt;
* MDL-55074&lt;br /&gt;
&lt;br /&gt;
= Promote the content of each page rather than the peripheral sections (blocks) =&lt;br /&gt;
* Users affected: new moodle users, experienced moodle users&lt;br /&gt;
* The problem: blocks displayed around the content compete for attention and real-estate in the page&lt;br /&gt;
* The proposed solution: Move the blocks regions into an expandable menu&lt;br /&gt;
* Criteria for success: the content of each page should be the first thing that grabs your focus, blocks should still be discoverable and usable if needed&lt;br /&gt;
* MDL-55075&lt;br /&gt;
&lt;br /&gt;
= The visual design of Moodle should look distinct from older versions =&lt;br /&gt;
* Users affected: new moodle users, themers&lt;br /&gt;
* The problem: We have not updated the look of the default theme in several years&lt;br /&gt;
* The proposed solution: Implement some new distinct styling in the new Moodle theme&lt;br /&gt;
* Criteria for success: The new moodle theme should look visually distinct. There should only be a minimum amount of custom styling for themers to override when extending this theme&lt;br /&gt;
* MDL-55076&lt;br /&gt;
&lt;br /&gt;
= Every page with settings should use a consistent, recognisable UI element to get to the settings =&lt;br /&gt;
* Users affected: all moodle users&lt;br /&gt;
* The problem: Settings pages are buried in the navigation tree in inconsistent locations&lt;br /&gt;
* The proposed solution: Create a settings navigation renderable that shows a gear icon on the top right of the page and takes you straight to the settings page. Update all pages with settings in moodle to use the new thing. &lt;br /&gt;
* Criteria for success: All pages with settings in Moodle should show a gear icon which will take you to the settings page when clicked.&lt;br /&gt;
* MDL-55077&lt;br /&gt;
&lt;br /&gt;
= Add lots of settings to the new theme so it can be used for many sites without installing a child-theme =&lt;br /&gt;
* Users affected: new moodle users&lt;br /&gt;
* The problem: Installing themes is hard/not possible in some environments. The new theme should be customisable enough to make it usable just by changing settings.&lt;br /&gt;
* The proposed solution: Review settings provided by community themes and add the common ones to this new theme.&lt;br /&gt;
* Criteria for success: Colours, fonts, logos should be customisable as well as additional settings supported by most community themes.&lt;br /&gt;
* MDL-55078&lt;br /&gt;
&lt;br /&gt;
= Don&#039;t break existing themes or require plugin developers to do anything new =&lt;br /&gt;
* Users affected: developers and admins&lt;br /&gt;
* The problem: Not everyone will be interested in all these new changes, or has the resources to redesign their theme immediately.   Likewise developers have enough to do right now and life for everyone will be a lot easier if we can maintain backward compatibility from 3.2.&lt;br /&gt;
* The proposed solution: Where core changes are required, make sure they work OK on as many existing themes as possible.&lt;br /&gt;
* Criteria for success: Themes still continue working and looking good.&lt;br /&gt;
*&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50009</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50009"/>
		<updated>2016-05-10T16:30:44Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* How we support 110 languages */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How to support over 100 languages===&lt;br /&gt;
&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [https://docs.moodle.org/dev/Category:Tutorial Other tutorials in these docs]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50008</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50008"/>
		<updated>2016-05-10T16:25:34Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How we support 110 languages===&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on separate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [https://docs.moodle.org/dev/Category:Tutorial Other tutorials in these docs]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50007</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50007"/>
		<updated>2016-05-10T16:25:18Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How we support 110 languages===&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.  If the code is long, it could be placed on seperate pages.  A good reference for style is [[Moodle_Mobile_Developing_a_plugin_tutorial]] and [[Blocks]].&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [https://docs.moodle.org/dev/Category:Tutorial Other tutorials in these docs]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_Mobile_2_(Ionic_1)_Developing_a_plugin_tutorial_part_2&amp;diff=50006</id>
		<title>Moodle Mobile 2 (Ionic 1) Developing a plugin tutorial part 2</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_Mobile_2_(Ionic_1)_Developing_a_plugin_tutorial_part_2&amp;diff=50006"/>
		<updated>2016-05-10T16:23:53Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle Mobile}}&lt;br /&gt;
{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
In this tutorial we are going to extend the notes add-on functionality&lt;br /&gt;
&lt;br /&gt;
== Add-on spec ==&lt;br /&gt;
&lt;br /&gt;
We want to develop a plugin that will display a new option at course level (at the same line that contents, participants and grades).&lt;br /&gt;
&lt;br /&gt;
This option will display all the course notes for all the participants in the course (it&#039;s suitable for teachers).&lt;br /&gt;
&lt;br /&gt;
A couple of screenshots with the desired result:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
| [[File:MoodleMobile2Tutorial201.png|thumb|Initial  view]]&lt;br /&gt;
| [[File:MoodleMobile2Tutorial202.png|thumb|Note types view]]&lt;br /&gt;
| [[File:MoodleMobile2Tutorial203.png|thumb|Notes view]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Steps ==&lt;br /&gt;
&lt;br /&gt;
=== Set up your development environment ===&lt;br /&gt;
&lt;br /&gt;
Please, read [[Setting up your development environment for Moodle Mobile 2]]&lt;br /&gt;
&lt;br /&gt;
=== Set up your Moodle installation ===&lt;br /&gt;
&lt;br /&gt;
Enable debugging, disable caches, etc... the typical settings for developing.&lt;br /&gt;
&lt;br /&gt;
Enable the Mobile Service via Admin / Plugins / Web Services / Mobile&lt;br /&gt;
&lt;br /&gt;
=== Develop the Moodle Web Services you are going to need ===&lt;br /&gt;
&lt;br /&gt;
In this case we&#039;ll use an existing web service (core_notes_get_course_notes) that is already available in the Moodle Mobile app service, if you need custom functions you will need to develop a local plugin including there your new Web Services (see https://moodle.org/plugins/view/local_wstemplate) and create a custom service.&lt;br /&gt;
&lt;br /&gt;
=== Develop the Moodle Mobile add-on ===&lt;br /&gt;
&lt;br /&gt;
The full source code can be found here: https://github.com/moodlehq/moodlemobile2/tree/master/www/addons/notes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/main.js&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
angular.module(&#039;mm.addons.notes&#039;, [])&lt;br /&gt;
&lt;br /&gt;
.config(function($stateProvider) {&lt;br /&gt;
&lt;br /&gt;
    $stateProvider&lt;br /&gt;
&lt;br /&gt;
    .state(&#039;site.notes-types&#039;, {&lt;br /&gt;
        url: &#039;/notes-types&#039;,&lt;br /&gt;
        views: {&lt;br /&gt;
            &#039;site&#039;: {&lt;br /&gt;
                templateUrl: &#039;addons/notes/templates/types.html&#039;,&lt;br /&gt;
                controller: &#039;mmaNotesTypesCtrl&#039;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
        params: {&lt;br /&gt;
            course: null&lt;br /&gt;
        }&lt;br /&gt;
    })&lt;br /&gt;
&lt;br /&gt;
    .state(&#039;site.notes-list&#039;, {&lt;br /&gt;
        url: &#039;/notes-list&#039;,&lt;br /&gt;
        views: {&lt;br /&gt;
            &#039;site&#039;: {&lt;br /&gt;
                templateUrl: &#039;addons/notes/templates/list.html&#039;,&lt;br /&gt;
                controller: &#039;mmaNotesListCtrl&#039;&lt;br /&gt;
            }&lt;br /&gt;
        },&lt;br /&gt;
        params: {&lt;br /&gt;
            courseid: null,&lt;br /&gt;
            type: null&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
})&lt;br /&gt;
&lt;br /&gt;
.run(function($mmUserDelegate, $mmaNotesHandlers, $mmCoursesDelegate, $mmaNotes) {&lt;br /&gt;
&lt;br /&gt;
    // Register plugin on course list.&lt;br /&gt;
    $mmCoursesDelegate.registerPlugin(&#039;mmaNotes&#039;, function() {&lt;br /&gt;
&lt;br /&gt;
        if ($mmaNotes.isPluginViewNotesEnabled()) {&lt;br /&gt;
            return {&lt;br /&gt;
                icon: &#039;ion-ios-list&#039;,&lt;br /&gt;
                state: &#039;site.notes-types&#039;,&lt;br /&gt;
                title: &#039;mma.notes.notes&#039;&lt;br /&gt;
            };&lt;br /&gt;
        }&lt;br /&gt;
    });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we declare the plugin, and register the Plugin (this means that the plugin will be displayed in the course main menu.&lt;br /&gt;
&lt;br /&gt;
Note also that we are declaring the states (views) the plugin will support, in this case there are two views: &lt;br /&gt;
* notes-types: Is a list that display the different note types available (site, course, personal).&lt;br /&gt;
* notes-lists: that will display a list of notes for the type selected in the previous view.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/templates/types.html&#039;&#039;&#039; and &#039;&#039;&#039;www/addons/notes/templates/list.html&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
These files contains the templates used for the view, the first one is very simple since it only links to the different note types.&lt;br /&gt;
&lt;br /&gt;
The second one is more complex since requires a controller that is going to do all the logic for retrieving the note and prepare them to be displayed.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/controllers/types.js&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This is the controller that inject data in the types.html view, the code is pretty simple:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
angular.module(&#039;mm.addons.notes&#039;)&lt;br /&gt;
.controller(&#039;mmaNotesTypesCtrl&#039;, function($scope, $stateParams) {&lt;br /&gt;
    var course = $stateParams.course,&lt;br /&gt;
        courseid = course.id;&lt;br /&gt;
&lt;br /&gt;
    $scope.courseid = courseid;&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It just make available in the $scope the courseid, that is required because is passed as a state parameter for the list view.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/controllers/list.js&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
This controller is the one that will render in the list view the notes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
.controller(&#039;mmaNotesListCtrl&#039;, function($scope, $stateParams, $mmUtil, $mmaNotes, $mmSite, $translate) {&lt;br /&gt;
&lt;br /&gt;
    var courseid = $stateParams.courseid,&lt;br /&gt;
        type = $stateParams.type;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Here we retrieved the state parameters (the course id and the type of notes) that were declared in the types.html view.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    function fetchNotes(refresh) {&lt;br /&gt;
        return $mmaNotes.getNotes(courseid, refresh).then(function(notes) {&lt;br /&gt;
            notes = notes[type + &#039;notes&#039;];&lt;br /&gt;
&lt;br /&gt;
            return $mmaNotes.getNotesUserData(notes, courseid).then(function(notes) {&lt;br /&gt;
                $scope.notes = notes;&lt;br /&gt;
            });&lt;br /&gt;
&lt;br /&gt;
        }, function(message) {&lt;br /&gt;
            $mmUtil.showErrorModal(message);&lt;br /&gt;
        });&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The fetchNotes function is responsible of using the Notes service getNotes to retrieve the data, note that we use an additional function getNotesUserData to retrieve the full user profile information (since via getNotes we only get the userid)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
fetchNotes().then(function() {&lt;br /&gt;
        // Add log in Moodle.&lt;br /&gt;
        $mmSite.write(&#039;core_notes_view_notes&#039;, {&lt;br /&gt;
            courseid: courseid,&lt;br /&gt;
            userid: 0&lt;br /&gt;
        });&lt;br /&gt;
    })&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
After retrieving the notes, we do logging in Moodle (so the actions are registered in the web interface)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    $scope.refreshNotes = function() {&lt;br /&gt;
        fetchNotes(true).finally(function() {&lt;br /&gt;
            $scope.$broadcast(&#039;scroll.refreshComplete&#039;);&lt;br /&gt;
        });&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This function is triggered by the &amp;quot;Pull down to refresh&amp;quot; action in order to refresh the view (empty the cache), note that the true parameter in the fetchNotes function means to not use cache.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/services/notes.js&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
The notes services holds all the main plugin logic, it&#039;s responsible of checking if the plugin is available, retrieve information for the server and format the information so it can be rendered in the view by the controller.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    self.isPluginViewNotesEnabled = function() {&lt;br /&gt;
        var infos;&lt;br /&gt;
&lt;br /&gt;
        if (!$mmSite.isLoggedIn()) {&lt;br /&gt;
            return false;&lt;br /&gt;
        } else if (!$mmSite.canUseAdvancedFeature(&#039;enablenotes&#039;)) {&lt;br /&gt;
            return false;&lt;br /&gt;
        } else if (!$mmSite.wsAvailable(&#039;core_notes_get_course_notes&#039;)) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Here we checked if the plugin is enabled, the user must logged in, enablenotes should be enabled in the Moodle global settings and the core_notes_get_course_notes function should be available.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    self.getNotes = function(courseid, refresh) {&lt;br /&gt;
&lt;br /&gt;
        $log.debug(&#039;Get notes for course &#039; + courseid);&lt;br /&gt;
&lt;br /&gt;
        var data = {&lt;br /&gt;
                courseid : courseid&lt;br /&gt;
            },&lt;br /&gt;
            presets = {};&lt;br /&gt;
        if (refresh) {&lt;br /&gt;
            presets.getFromCache = false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return $mmSite.read(&#039;core_notes_get_course_notes&#039;, data, presets);&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Here we retrieve the notes information from Moodle via Web Services, note that the refresh function is used for invalidating the cache (for example, when the user performs a pull down to refresh).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    self.getNotesUserData = function(notes, courseid) {&lt;br /&gt;
        var promises = [];&lt;br /&gt;
&lt;br /&gt;
        angular.forEach(notes, function(note) {&lt;br /&gt;
            var promise = $mmUser.getProfile(note.userid, courseid, true);&lt;br /&gt;
            promises.push(promise);&lt;br /&gt;
            promise.then(function(user) {&lt;br /&gt;
                note.userfullname = user.fullname;&lt;br /&gt;
                note.userprofileimageurl = user.profileimageurl;&lt;br /&gt;
            }, function() {&lt;br /&gt;
                // Error getting profile. Set default data.&lt;br /&gt;
                return $translate(&#039;mma.notes.userwithid&#039;, {id: note.userid}).then(function(str) {&lt;br /&gt;
                    note.userfullname = str;&lt;br /&gt;
                });&lt;br /&gt;
            });&lt;br /&gt;
        });&lt;br /&gt;
        return $q.all(promises).then(function() {&lt;br /&gt;
            return notes;&lt;br /&gt;
        });&lt;br /&gt;
    };&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Since getNotes returns only userids, we need to retrieve the complete user information in order to be able to display his full name and profile image. We use the $mmUser service getProfile function.&lt;br /&gt;
&lt;br /&gt;
[[Category: Mobile]]&lt;br /&gt;
[[Category: Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_Mobile_2_(Ionic_1)_Developing_a_plugin_tutorial&amp;diff=50005</id>
		<title>Moodle Mobile 2 (Ionic 1) Developing a plugin tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_Mobile_2_(Ionic_1)_Developing_a_plugin_tutorial&amp;diff=50005"/>
		<updated>2016-05-10T16:23:27Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle Mobile}}&lt;br /&gt;
{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This tutorial describes all the steps needed for developing an add-on for the Moodle Mobile app.&lt;br /&gt;
&lt;br /&gt;
In this tutorial we make the following assumptions:&lt;br /&gt;
&lt;br /&gt;
* You have a medium/good skills/understand of AngularJS/Ionic, PHP and Moodle architecture&lt;br /&gt;
* You know what a Web Service is and how it works in Moodle&lt;br /&gt;
* The plugin you are going to develop requires a Web Service in your Moodle installation to work&lt;br /&gt;
&lt;br /&gt;
There is a second part of this tutorial where we extend the add-on features [[Moodle Mobile Developing a plugin tutorial part 2]]&lt;br /&gt;
&lt;br /&gt;
== Add-on spec ==&lt;br /&gt;
&lt;br /&gt;
We want to develop a plugin that will display a new button in the user profile for adding new notes to the user. This plugin is suitable for course managers of teachers.&lt;br /&gt;
&lt;br /&gt;
A couple of screenshots with the desired result:&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
| [[File:MoodleMobile2Tutorial01.png|thumb|Initial  view]]&lt;br /&gt;
| [[File:MoodleMobile2Tutorial02.png|thumb|Course contents view]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Steps ==&lt;br /&gt;
&lt;br /&gt;
=== Set up your development environment ===&lt;br /&gt;
&lt;br /&gt;
Please, read [[Setting up your development environment for Moodle Mobile 2]]&lt;br /&gt;
&lt;br /&gt;
=== Set up your Moodle installation ===&lt;br /&gt;
&lt;br /&gt;
Enable debugging, disable caches, etc... the typical settings for developing.&lt;br /&gt;
&lt;br /&gt;
Enable the Mobile Service via Admin / Plugins / Web Services / Mobile&lt;br /&gt;
&lt;br /&gt;
=== Develop the Moodle Web Services you are going to need ===&lt;br /&gt;
&lt;br /&gt;
In this case we&#039;ll use an existing web service (core_notes_create_notes) that is already available in the Moodle Mobile app service, if you need custom functions you will need to develop a local plugin including there your new Web Services (see https://moodle.org/plugins/view/local_wstemplate) and create a custom service.&lt;br /&gt;
&lt;br /&gt;
=== Develop the Moodle Mobile add-on ===&lt;br /&gt;
&lt;br /&gt;
The full source code can be found here: https://github.com/moodlehq/moodlemobile2/tree/master/www/addons/notes&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/main.js&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
angular.module(&#039;mm.addons.notes&#039;, [])&lt;br /&gt;
&lt;br /&gt;
.run(function($mmUserDelegate, $mmaNotesHandlers) {&lt;br /&gt;
&lt;br /&gt;
    $mmUserDelegate.registerPlugin(&#039;mmaNotes:addNote&#039;, $mmaNotesHandlers.addNote);&lt;br /&gt;
&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here we declare the plugin, and register the Plugin (this means that the plugin will be displayed in the User profile.&lt;br /&gt;
&lt;br /&gt;
We will use the $mmaNotesHandlers service for holding all the code related to the plugin availability and main functions&lt;br /&gt;
&lt;br /&gt;
There are more delegates for registering your plugin, see:&lt;br /&gt;
* www/addons/mod_forum/main.js (Module delegate, and module actions delegate)&lt;br /&gt;
* www/addons/messages/main.js (Main side menu delegate, and multiple delegates for the user profile)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/services/handlers.js&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
self.isEnabled = function() {&lt;br /&gt;
    return $mmaNotes.isPluginEnabled();&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
self.isEnabledForUser = function(user, courseId) {&lt;br /&gt;
   // Active course required.&lt;br /&gt;
   return courseId &amp;amp;&amp;amp; user.id != $mmSite.getUserId();&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These are mandatory functions that will check our plugin availability, the first one will rely in the $mmaNotes service (isPluginEnabled function), the second ones checks that the user profile is being viewed inside a course (because the WS requires it) and that the current user is not the required user (so you don&#039;t see the buttons in your own profile).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
        self.getController = function(user, courseid) {&lt;br /&gt;
&lt;br /&gt;
            return function($scope) {&lt;br /&gt;
&lt;br /&gt;
                // Button title.&lt;br /&gt;
                $scope.title = &#039;mma.notes.addnewnote&#039;;&lt;br /&gt;
&lt;br /&gt;
                $ionicModal.fromTemplateUrl(&#039;addons/notes/templates/add.html&#039;, {&lt;br /&gt;
                    scope: $scope,&lt;br /&gt;
                    animation: &#039;slide-in-up&#039;&lt;br /&gt;
                }).then(function(m) {&lt;br /&gt;
                    $scope.modal = m;&lt;br /&gt;
                });&lt;br /&gt;
&lt;br /&gt;
                $scope.closeModal = function(){&lt;br /&gt;
                    $scope.modal.hide();&lt;br /&gt;
                };&lt;br /&gt;
&lt;br /&gt;
                $scope.addNote = function(){&lt;br /&gt;
                    // Freeze the add note button.&lt;br /&gt;
                    $scope.processing = true;&lt;br /&gt;
&lt;br /&gt;
                    $mmaNotes.addNote(user.id, courseid, $scope.note.publishstate, $scope.note.text).then(function() {&lt;br /&gt;
                        $translate(&#039;mma.notes.eventnotecreated&#039;).then(function(str) {&lt;br /&gt;
                            $ionicLoading.show({&lt;br /&gt;
                                template: str,&lt;br /&gt;
                                duration: 2000&lt;br /&gt;
                            });&lt;br /&gt;
                        });&lt;br /&gt;
                    }, function(error) {&lt;br /&gt;
                        $mmUtil.showErrorModal(error);&lt;br /&gt;
                    }).finally(function() {&lt;br /&gt;
                        $scope.closeModal();&lt;br /&gt;
                    });&lt;br /&gt;
                };&lt;br /&gt;
&lt;br /&gt;
                $scope.action = function($event) {&lt;br /&gt;
                    $event.preventDefault();&lt;br /&gt;
                    $event.stopPropagation();&lt;br /&gt;
&lt;br /&gt;
                    $scope.note = {&lt;br /&gt;
                        publishstate: &#039;personal&#039;,&lt;br /&gt;
                        text: &#039;&#039;&lt;br /&gt;
                    };&lt;br /&gt;
                    $scope.processing = false;&lt;br /&gt;
&lt;br /&gt;
                    $scope.modal.show();&lt;br /&gt;
                };&lt;br /&gt;
            };&lt;br /&gt;
        };&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These is the main function code, it does the following:&lt;br /&gt;
* $scope.title = &#039;mma.notes.addnewnote&#039;; This sets the button title, note that we reference to the addnewnote string that is in the www/addons/notes/lang/en.json file (we need to prefix the string id to identify the plugin)&lt;br /&gt;
* $ionicModal.fromTemplateUrl - Creates the modal we are going to use for displaying the form, the HTML code of the form is in www/addons/notes/templates/add.html&lt;br /&gt;
* $scope.closeModal - Helper function for closing the modal inside the modal via a button&lt;br /&gt;
* $scope.addNote - This function will be called when the user clicks the &amp;quot;Add a note&amp;quot; button in the modal, it will use the $mmaNotes service that handles all the logic WS logic for creating the note&lt;br /&gt;
* $scope.action - This function will be called when the user clicks the &amp;quot;Add a note&amp;quot; button in the user profile view, it will open the modal and set the default values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;www/addons/notes/services/notes.js&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
angular.module(&#039;mm.addons.notes&#039;)&lt;br /&gt;
&lt;br /&gt;
.factory(&#039;$mmaNotes&#039;, function($mmSite, $log, $q) {&lt;br /&gt;
    $log = $log.getInstance(&#039;$mmaNotes&#039;);&lt;br /&gt;
&lt;br /&gt;
    var self = {};&lt;br /&gt;
&lt;br /&gt;
    self.addNote = function(userId, courseId, publishState, noteText) {&lt;br /&gt;
        var data = {&lt;br /&gt;
            &amp;quot;notes[0][userid]&amp;quot; : userId,&lt;br /&gt;
            &amp;quot;notes[0][publishstate]&amp;quot;: publishState,&lt;br /&gt;
            &amp;quot;notes[0][courseid]&amp;quot;: courseId,&lt;br /&gt;
            &amp;quot;notes[0][text]&amp;quot;: noteText,&lt;br /&gt;
            &amp;quot;notes[0][format]&amp;quot;: 1&lt;br /&gt;
        };&lt;br /&gt;
        return $mmSite.write(&#039;core_notes_create_notes&#039;, data);&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    self.isPluginEnabled = function() {&lt;br /&gt;
        var infos;&lt;br /&gt;
&lt;br /&gt;
        if (!$mmSite.isLoggedIn()) {&lt;br /&gt;
            return false;&lt;br /&gt;
        } else if (!$mmSite.canUseAdvancedFeature(&#039;enablenotes&#039;)) {&lt;br /&gt;
            return false;&lt;br /&gt;
        } else if (!$mmSite.wsAvailable(&#039;core_notes_create_notes&#039;)) {&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    return self;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This file contains the notes service:&lt;br /&gt;
* isPluginEnabled - Checks if the notes functionality is available by checking Moodle settings and the required WS availability&lt;br /&gt;
* addNote - Will call the remote WS for adding the note via the $mmSite.write helper method (the $mmService has also a read method for retrieving data)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;/www/addons/notes/templates/add.html&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;ion-modal-view class=&amp;quot;product edit create&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;form name=&amp;quot;itemEdit&amp;quot; ng-submit=&amp;quot;addNote()&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;ion-header-bar class=&amp;quot;bar-header&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;h1 class=&amp;quot;title&amp;quot;&amp;gt;{{ &#039;mma.notes.addnewnote&#039; | translate }}&amp;lt;/h1&amp;gt;&lt;br /&gt;
            &amp;lt;a class=&amp;quot;button&amp;quot; ng-click=&amp;quot;closeModal()&amp;quot;&amp;gt;{{ &#039;mm.core.cancel&#039; | translate }}&amp;lt;/a&amp;gt;&lt;br /&gt;
        &amp;lt;/ion-header-bar&amp;gt;&lt;br /&gt;
        &amp;lt;ion-content has-bouncing=&amp;quot;true&amp;quot;&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label class=&amp;quot;item item-input item-select&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;div class=&amp;quot;input-label&amp;quot;&amp;gt;&lt;br /&gt;
                          {{ &#039;mma.notes.publishstate&#039; | translate }}&lt;br /&gt;
                        &amp;lt;/div&amp;gt;&lt;br /&gt;
                        &amp;lt;select ng-model=&amp;quot;note.publishstate&amp;quot; name=&amp;quot;publishstate&amp;quot;&amp;gt;&lt;br /&gt;
                            &amp;lt;option value=&amp;quot;personal&amp;quot;&amp;gt;{{ &#039;mma.notes.personalnotes&#039; | translate }}&amp;lt;/option&amp;gt;&lt;br /&gt;
                            &amp;lt;option value=&amp;quot;course&amp;quot;&amp;gt;{{ &#039;mma.notes.coursenotes&#039; | translate }}&amp;lt;/option&amp;gt;&lt;br /&gt;
                            &amp;lt;option value=&amp;quot;site&amp;quot;&amp;gt;{{ &#039;mma.notes.sitenotes&#039; | translate }}&amp;lt;/option&amp;gt;&lt;br /&gt;
                        &amp;lt;/select&amp;gt;&lt;br /&gt;
                    &amp;lt;/label&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;row&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;div class=&amp;quot;col&amp;quot;&amp;gt;&lt;br /&gt;
                    &amp;lt;label class=&amp;quot;item item-input text&amp;quot;&amp;gt;&lt;br /&gt;
                        &amp;lt;textarea placeholder=&amp;quot;{{ &#039;mma.notes.note&#039; | translate }}&amp;quot; rows=&amp;quot;5&amp;quot; ng-model=&amp;quot;note.text&amp;quot; name=&amp;quot;text&amp;quot; lose-focus-on-return required=&amp;quot;required&amp;quot;&amp;gt;&amp;lt;/textarea&amp;gt;&lt;br /&gt;
                    &amp;lt;/label&amp;gt;&lt;br /&gt;
                &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
            &amp;lt;div class=&amp;quot;padding&amp;quot;&amp;gt;&lt;br /&gt;
                &amp;lt;button type=&amp;quot;submit&amp;quot; class=&amp;quot;button button-block&amp;quot; ng-disabled=&amp;quot;processing || !note.text.length || note.text.length &amp;lt; 2&amp;quot;&amp;gt;&lt;br /&gt;
                    {{ &#039;mma.notes.addnewnote&#039; | translate }}&lt;br /&gt;
                &amp;lt;/button&amp;gt;&lt;br /&gt;
            &amp;lt;/div&amp;gt;&lt;br /&gt;
        &amp;lt;/ion-content&amp;gt;&lt;br /&gt;
    &amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/ion-modal-view&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This file includes the code for the modal. As you can see the close button will call the closeModal() function meanwhile the Add a note button will submit the form that will invoke the addNote function&lt;br /&gt;
&lt;br /&gt;
For more information, refer to http://ionicframework.com/docs/api/service/$ionicModal/&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
[[Moodle Mobile Developing a plugin tutorial part 2]]&lt;br /&gt;
&lt;br /&gt;
[[Category: Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50004</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50004"/>
		<updated>2016-05-10T16:20:00Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* See also these older tutorials */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How we support 110 languages===&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [https://docs.moodle.org/dev/Category:Tutorial Other tutorials in these docs]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50003</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50003"/>
		<updated>2016-05-10T16:18:54Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* See also these older tutorials */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How we support 110 languages===&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
* [[Category:Tutorial|Other Tutorials in these docs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50002</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50002"/>
		<updated>2016-05-10T16:17:52Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* See also these older tutorials */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How we support 110 languages===&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50001</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50001"/>
		<updated>2016-05-10T16:14:47Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How we support 110 languages===&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=See also these older tutorials =&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50000</id>
		<title>Tutorial</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tutorial&amp;diff=50000"/>
		<updated>2016-05-10T16:13:49Z</updated>

		<summary type="html">&lt;p&gt;Dougiamas: /* TODO */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Welcome to Moodle development!&lt;br /&gt;
&lt;br /&gt;
This is a tutorial to help you learn how to write plugins for Moodle from start to finish, while showing you how to navigate the most important developer documentation along the way.&lt;br /&gt;
&lt;br /&gt;
PRE-REQUISITES:  We assume you are fairly comfortable with PHP in general and that you are able to install a database and web server on your local machine.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
===Setting up your development environment===&lt;br /&gt;
===The Moodle development framework===&lt;br /&gt;
===What type of plugin are you developing?===&lt;br /&gt;
==Let&#039;s make a plugin==&lt;br /&gt;
===The skeleton of your plugin===&lt;br /&gt;
===Basic page structure===&lt;br /&gt;
===How we support 110 languages===&lt;br /&gt;
===Add content to your page===&lt;br /&gt;
===Adding your plugin into Moodle&#039;s navigation===&lt;br /&gt;
===Database queries===&lt;br /&gt;
===Creating your own database tables===&lt;br /&gt;
===Supporting access permissions: roles, capabilities and contexts===&lt;br /&gt;
===Adding web forms===&lt;br /&gt;
===Maintaining good security===&lt;br /&gt;
===Handling files===&lt;br /&gt;
===Adding Javascript===&lt;br /&gt;
===Adding events and logging===&lt;br /&gt;
===Web Services and AJAX===&lt;br /&gt;
===Using caching to improve performance===&lt;br /&gt;
===Supporting backup and restore===&lt;br /&gt;
===Supporting automated testing===&lt;br /&gt;
==Publishing your plugin==&lt;br /&gt;
===Adding your plugin to moodle.org===&lt;br /&gt;
===Supporting your plugin===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=TODO=&lt;br /&gt;
Finishing this tutorial:&lt;br /&gt;
# About one or two screens for each section with a very generic overview for beginners, containing links to relevant docs WITH COMMENTS ABOUT QUALITY, USEFULNESS, CAVEATS etc.&lt;br /&gt;
# Go through all the linked pages and make sure they are current and accurate.&lt;br /&gt;
# Add a worked example to this page, so that each section has suggestions about things to add to the admin tool being built as an exercise.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also these older tutorials ==&lt;br /&gt;
* [[Blocks|A Step-by-step Guide To Creating Blocks]] &lt;br /&gt;
* [[NEWMODULE Tutorial]]&lt;br /&gt;
* [http://dev.moodle.org Introduction to Moodle programming (based on Moodle 1.8)]&lt;br /&gt;
* [[Moodle_Mobile_Developing_a_plugin_tutorial|Moodle Mobile plugin tutorial]]&lt;/div&gt;</summary>
		<author><name>Dougiamas</name></author>
	</entry>
</feed>