<?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=Scaroodle</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=Scaroodle"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Scaroodle"/>
	<updated>2026-06-27T19:17:25Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=61354</id>
		<title>Acceptance testing/Compatibility changes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Acceptance_testing/Compatibility_changes&amp;diff=61354"/>
		<updated>2021-09-19T08:38:26Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: &amp;quot;Edit settings&amp;quot; is now &amp;quot;Settings&amp;quot;. Refs: MDL-72093&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;As new features are developed for Moodle, some UI changes can cause changes which unfortunately affect behat feature files. This page is intended to document important compatibility changes for behat test developers.&lt;br /&gt;
= Compatibility changes =&lt;br /&gt;
== Moodle 3.3 ==&lt;br /&gt;
=== And I follow &amp;quot;Course 1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;lt;br&amp;gt;And I am on &amp;quot;Course 1&amp;quot; course homepage with editing mode on&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.1.6, 3.2.3 and up. &lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on site homepage&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Scenario: I am on the course homepage&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    Then I should see &amp;quot;Topic 1&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
UI changes in the new dashboard mean the existing &#039;loose&#039; step matches multiple values. The replacement step should help speed up your tests.&lt;br /&gt;
== Moodle 3.2 ==&lt;br /&gt;
=== And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt;Summary&amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
|And I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    When I click on &amp;quot;Edit settings&amp;quot; &amp;quot;link&amp;quot; in the &amp;quot;Administration&amp;quot; &amp;quot;block&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;teacher1&amp;quot;&lt;br /&gt;
    And I am on &amp;quot;Course 1&amp;quot; course homepage&lt;br /&gt;
    When I navigate to &amp;quot;Edit settings&amp;quot; in current page administration&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt;Why did this change?&amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
&lt;br /&gt;
Note: since 4.0 &#039;&#039;Edit Settings&#039;&#039; has been changed into &#039;&#039;Settings&#039;&#039;. Refs: MDL-72093.&lt;br /&gt;
=== And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot; ===&lt;br /&gt;
&amp;lt;b&amp;gt; Summary &amp;lt;/b&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|Previous step/s:&lt;br /&gt;
| And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;My courses &amp;gt; C1&amp;quot;&amp;lt;br&amp;gt;And I navigate to &amp;quot;Site blogs&amp;quot; node in &amp;quot;Site pages&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|New step/s&lt;br /&gt;
| And I navigate to course participants&lt;br /&gt;
|-&lt;br /&gt;
|Backported to:&lt;br /&gt;
|Moodle 3.2.1, 3.1.4 and up. &lt;br /&gt;
|}&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
|+Examples&lt;br /&gt;
|-&lt;br /&gt;
|Before&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Scenario: Going to course settings&lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to &amp;quot;Participants&amp;quot; node in &amp;quot;Current course &amp;gt; C1&amp;quot;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
|After&lt;br /&gt;
|&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
Scenario: Going to course participants &lt;br /&gt;
    When I log in as &amp;quot;student1&amp;quot;&lt;br /&gt;
    And I follow &amp;quot;Course 1&amp;quot;&lt;br /&gt;
    And I navigate to course participants&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;b&amp;gt; Why did this change? &amp;lt;/b&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The boost theme changes how navigation works and the new steps are compatible with boost and bootstrap based themes.&lt;br /&gt;
== Moodle 3.1 ==&lt;br /&gt;
=== Behat migration from 2.5 to 3.x ===&lt;br /&gt;
Behat 3 brings a lot of extensibility and modularity but there are compatibility changes for running tests and writing step definitions. See [[Acceptance testing/Migrating from Behat 2.5 to 3.x in Moodle]] for fully details when coming from earlier versions of Moodle.&lt;br /&gt;
= See also =&lt;br /&gt;
* [[Running_acceptance_test]]&lt;br /&gt;
[[Category:Quality Assurance]]&lt;br /&gt;
[[Category:Behat]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.9.10_release_notes&amp;diff=61277</id>
		<title>Moodle 3.9.10 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.9.10_release_notes&amp;diff=61277"/>
		<updated>2021-09-13T06:23:21Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Add MDL-72494, being critical for the recent regression in M93 (Fixed in M94)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;p class=&amp;quot;note&amp;quot;&amp;gt;&#039;&#039;&#039;This version of Moodle is no longer supported for general bug fixes.&#039;&#039;&#039; You are encouraged to [[:en:Upgrading|upgrade]] to a supported version of Moodle.&amp;lt;/p&amp;gt;&lt;br /&gt;
[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Release date: 13 September 2021&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.9.10%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.9.10].&lt;br /&gt;
==Backported bug fixes==&lt;br /&gt;
* MDL-72494 - Cannot change course format with Chrome 93.0&lt;br /&gt;
* MDL-72312 - PHP 7.2 tests failing in 3.10 &amp;amp; 3.9, caused by buggy php-igbinary extension&lt;br /&gt;
* MDL-72265 - Backup code added in MDL-56310 incorrectly checks moodle/role:safeoverride for users who already have moodle/role:override&lt;br /&gt;
==Backported security improvements==&lt;br /&gt;
* MDL-72014 - Update grunt and some components to avoid some security reports&lt;br /&gt;
* MDL-72187 - Log visibility change of log stores&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.9.9 release notes]]&lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.9]]&lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.9.10]]&lt;br /&gt;
[[es:Notas de Moodle 3.9.10]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Travis_integration&amp;diff=58360</id>
		<title>Travis integration</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Travis_integration&amp;diff=58360"/>
		<updated>2021-02-19T21:05:56Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Fix typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Given the two notes below, you probably don&#039;t want to read this page. [[Github actions integration]] is much more likely to be what you want.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;Travis [https://mailchi.mp/3d439eeb1098/travis-ciorg-is-moving-to-travis-cicom has announced] that &#039;&#039;&#039;travis-ci.org will be closed down completely on December 31st 2020&#039;&#039;&#039;, with travis-ci.com becoming the unified place for all projects. More information can be found at:&lt;br /&gt;
* [https://docs.travis-ci.com/user/migrate/open-source-repository-migration Migrating repositories to travis-ci.com]&lt;br /&gt;
* Moodle Tracker: MDLSITE-6246&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;Travis [https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing has announced], November 2, 2020, that &#039;&#039;&#039;travis-ci.com won&#039;t be (unlimitedly) free anymore&#039;&#039;&#039;, with everybody getting some credits (processing time) once and, after using them, you must change to some of their (paid) plans. Few weeks later, November 24, 2020, [https://blog.travis-ci.com/oss-announcement they have published an update] specifically for Open Source. There, they recommend to contact them &#039;&#039;&amp;quot;for anything relating with your open source account&amp;quot;&#039;&#039;. Up to you!&lt;br /&gt;
More information can be found at:&lt;br /&gt;
* Moodle Tracker: MDL-70265&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Moodle core ==&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
&lt;br /&gt;
Moodle is regularly tested against a matrix of Databases, PHP Versions, and operating systems, however many developers do not have the resources available to run on many of these combinations before pushing an issue for integration as they are time-consuming to both set up and to run.&lt;br /&gt;
&lt;br /&gt;
There are many Continuous Integration tools available to developers, and Travis-CI is just one of those available to the Open Source community.&lt;br /&gt;
&lt;br /&gt;
Since version 3.0, Moodle includes a Travis configuration file in its repository. This configuration file configures and controls a Travis build across a matrix of testing environments. This allows developers pushing patches to Moodle to have their code unit tested before it reaches integration. The hope is that the availability of this integration should reduce the number of unit test failures seen during Integration.&lt;br /&gt;
&lt;br /&gt;
Note: Moodle HQ uses the Jenkins CI platform and this should be seen as the [https://ci.moodle.org/ canonical CI server for Moodle]. The Travis integration aims is to provide early warning to developers of any issues with their code.&lt;br /&gt;
&lt;br /&gt;
=== Usage ===&lt;br /&gt;
&lt;br /&gt;
Travis-CI is available and is usually configured to run automatically when pushing code, but it must be configured before first use.&lt;br /&gt;
&lt;br /&gt;
For the purpose of this documentation, it is assumed that you are pushing to a public Moodle repository on GitHub. Other integrations are supported, but the service available from Travis is only available to public repositories.&lt;br /&gt;
&lt;br /&gt;
=== Setup ===&lt;br /&gt;
&lt;br /&gt;
# [https://travis-ci.com/auth Sign in to Travis CI] using your GitHub account&lt;br /&gt;
# Once you’re signed in, and the initial synchronisation of your GitHub repositories has completed, go to your [https://travis-ci.com/profile profile page]&lt;br /&gt;
# Enable Travis CI for your clone of the Moodle repository [[File:moodle-travis-enable.png]]&lt;br /&gt;
# Click on the cog icon to configure the Integration&lt;br /&gt;
# Ensure that &amp;quot;Build pushed branches&amp;quot; is enabled [[File:moodle-travis-settings-2020.png]]&lt;br /&gt;
# Email notifications will be sent by default to the committer and the commit author. If you want to turn off email notifications for this repository, you can define an environment variable with name MOODLE_EMAIL and &amp;quot;no&amp;quot; as value.&lt;br /&gt;
# By default, the following jobs will be executed for each branch sent to github:&lt;br /&gt;
## GRUNT: 1 job that will check that all your javascript and scss has been properly built (see [[Grunt]]) and is part of the patch.&lt;br /&gt;
## CITESTS: 1 job that will perform a lightweight linting of your branch.&lt;br /&gt;
## PHPUNIT: 1 job that will run all the unit tests on your branch (using the lowest PHP version supported by the branch and PostgreSQL as database).&lt;br /&gt;
# If you want to change those defaults, you can use the following environment variables:&lt;br /&gt;
## MOODLE_DATABASE: With value &amp;quot;mysqli&amp;quot; to switch your runs to that database. With value &amp;quot;all&amp;quot; to run both PostgreSQL and MySQL unit tests.&lt;br /&gt;
## MOODLE_PHP: With value &amp;quot;all&amp;quot;, to run the unit tests both with the lowest and the highest PHP versions supported by the branch.&lt;br /&gt;
Note that adding more jobs will increase the time needed (and the credits consumed) for processing each branch, so be careful picking your fav configuration.&lt;br /&gt;
[[File:environment_variables.png|Define an environment variable]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== How do I start a build? ===&lt;br /&gt;
&lt;br /&gt;
It won&#039;t build immediately after setup. Builds start automatically when you push a change.&lt;br /&gt;
&lt;br /&gt;
== Moodle plugins ==&lt;br /&gt;
&lt;br /&gt;
See [https://moodlehq.github.io/moodle-plugin-ci/ Moodle Plugin CI repository] for setup instructions.&lt;br /&gt;
&lt;br /&gt;
Related discussions:&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=323384 Adding Travis CI support into your plugin]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=389744 Recent Travis-CI issues with plugins]&lt;br /&gt;
&lt;br /&gt;
=== Ignoring files and folders ===&lt;br /&gt;
&lt;br /&gt;
For some of the code analysis tools, it is important to ignore some files within the plugin because they might not be fixable, like a third party library. The all code analysis commands in this project ignore files and directories listed in the thirdpartylibs.xml plugin file. See https://docs.moodle.org/dev/Plugin_files#thirdpartylibs.xml for more info.&lt;br /&gt;
&lt;br /&gt;
==== Ignoring files ====&lt;br /&gt;
&lt;br /&gt;
Specifically for the codechecker command, you can ignore a single line, a section of a file or the whole file by using specific PHP comments. For details see this [[CodeSniffer]] wiki page.&lt;br /&gt;
In addition, you can ignore additional files by defining IGNORE_PATHS and/or IGNORE_NAMES environment variables in your .travis.yml file. These environment variables wont work for Grunt tasks, but will for everything else. Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
env:&lt;br /&gt;
 global:&lt;br /&gt;
  - MOODLE_BRANCH=MOODLE_35_STABLE&lt;br /&gt;
  - IGNORE_PATHS=vendor/widget,javascript/min-lib.js&lt;br /&gt;
  - IGNORE_NAMES=*-m.js,bad_lib.php&lt;br /&gt;
 matrix:&lt;br /&gt;
  - DB=pgsql&lt;br /&gt;
  - DB=mysqli&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Both environment variables take a CSV value. For IGNORE_PATHS, it takes relative file paths to ignore. File paths can be a simple string like foo/bar or a regular expression like /^foo\/bar/. For IGNORE_NAMES, it takes file names to ignore. File names can be a simple string like foo.php, a glob like *.php or a regular expression like /\.php$/.&lt;br /&gt;
&lt;br /&gt;
If you need to specify ignore paths for a specific command, then you can define additional environment variables. The variable names are the same as above, but prefixed with COMMANDNAME_. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
env:&lt;br /&gt;
 global:&lt;br /&gt;
  - MOODLE_BRANCH=MOODLE_35_STABLE&lt;br /&gt;
  - IGNORE_PATHS=vendor/widget,javascript/min-lib.js&lt;br /&gt;
  - IGNORE_NAMES=*-m.js,bad_lib.php&lt;br /&gt;
  - PHPUNIT_IGNORE_PATHS=$IGNORE_PATHS,cli&lt;br /&gt;
 matrix:&lt;br /&gt;
  - DB=pgsql&lt;br /&gt;
  - DB=mysqli&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In the above example, we are adding the cli path to our ignore paths for the PHPUnit command (this is also how you can ignore files for code coverage). Please note that this is a complete override and there is no merging with IGNORE_PATHS and IGNORE_NAMES. So, in the above, the PHPUnit command would not ignore the file names defined in IGNORE_NAMES.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Github actions integration]]: For information about the, also supported, integration with GitHub Actions.&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer tools]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=58242</id>
		<title>Git for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=58242"/>
		<updated>2021-01-26T20:22:40Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Add GH Actions too - Available soon even for Plugins&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for helping you get started on Moodle development with Git. For further details of Git, see [[:Category:Git]].&lt;br /&gt;
&lt;br /&gt;
== General workflow ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A reasonable knowledge of the Git basics is a good idea before you start to use it for development. If you are new to Git, you are encouraged to go to &#039;See also&#039; for some more general reading.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:git-pushpull-model.png|right|thumb|400px|Moodle development workflow with Git]]&lt;br /&gt;
Detailed explanation of the workflow can be found in the [[Process]] page. In short, the Moodle development with Git looks like this:&lt;br /&gt;
&lt;br /&gt;
* You as the contributor commit changes into your personal repository at your computer&lt;br /&gt;
* You push the changes into your public repository and publish links to your changes in the Moodle Tracker&lt;br /&gt;
* You request a peer review of your code from another developer&lt;br /&gt;
* When peer reviewer is happy they submit issue for integration&lt;br /&gt;
* Moodle integrators pull the changes from your public repository and if they like them, they put them into Moodle integration repository&lt;br /&gt;
* The integrated change is tested and finally pushed into Moodle production repository&lt;br /&gt;
* You update your local repository with all changes from the production repository and the next cycle may start again&lt;br /&gt;
&lt;br /&gt;
This workflow runs in roughly weekly cycles. The integration happens on Monday and Tuesday and the testing on Wednesday. On Thursday (or Friday if testing takes too long), the production repository moodle.git is usually updated with changes from the last development week.&lt;br /&gt;
&lt;br /&gt;
Most Moodle developers have their public repositories hosted at [http://github.com/ Github]. Alternatively you may want to try [http://gitorious.org Gitorious] or the legendary [http://repo.or.cz repo.or.cz]. In the examples in this guide we assume you&#039;ll set up your public repository at Github.&lt;br /&gt;
&lt;br /&gt;
When you first register on tracker you can not assign issues to yourself or send them for peer review. You will be added to the developers group after your first bug fix is integrated. Before that just comment on the issue with a link to your branch and component lead or another developer will send issue for peer review for you.&lt;br /&gt;
&lt;br /&gt;
== Installing Git on your computer ==&lt;br /&gt;
&lt;br /&gt;
Install Git on your computer. Most Linux distributions have Git available as a package to install. On Debian/Ubuntu, type &#039;&#039;&#039;&#039;sudo apt-get install git&#039;&#039;&#039;&#039; on the terminal. If you are on Mac, [http://code.google.com/p/git-osx-installer/ git-osx-installer] installs it in a few clicks. &lt;br /&gt;
&lt;br /&gt;
Immediately after the installation, set your name and contact e-mail. The name and e-mail will become part of your commits and they can&#039;t be changed later once your commits are accepted into the Moodle code. Therefore we ask contributors to use their real names written in capital letters, eg &amp;quot;John Smith&amp;quot; and not &amp;quot;john smith&amp;quot; or even &amp;quot;john5677&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
    git config --global user.name &amp;quot;Your Name&amp;quot;&lt;br /&gt;
    git config --global user.email yourmail@domain.tld&lt;br /&gt;
&lt;br /&gt;
Unless you are the repository maintainer, it is wise to set your Git to not push changes in file permissions:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.filemode false&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to verify that the your git installation is not performing any transformation between LFs and CRLFs. All Moodle &#039;&#039;&#039;uses only LFs&#039;&#039;&#039; and you should &#039;&#039;&#039;fetch/edit and push&#039;&#039;&#039; it that way (may need to configure your editor/IDE too). Note that having any &amp;quot;magic&amp;quot; enabled is known to cause [[Common unit test problems#The_test_file_.22evolution.test.22_should_not_contain_section_named_.22.5Blots_of_content.5D.22|problems with unit tests]] execution. So we recommend you to set:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.autocrlf false&lt;br /&gt;
&lt;br /&gt;
== Setting-up the public repository ==&lt;br /&gt;
&lt;br /&gt;
1. Go to [http://github.com/ Github] and create an account.&lt;br /&gt;
&lt;br /&gt;
2. Go to the [http://github.com/moodle/moodle official Moodle Github repository] and click on the Fork button. You now have your own Github Moodle repository.&lt;br /&gt;
&lt;br /&gt;
3. Now you need to set up your SSH public key, so you can push to your Github Moodle repository from your local Moodle repository. On Mac you can go on this [http://help.github.com/mac-key-setup/ Github help page]. If you are on another system, go to your Github administration page, to the section SSH Public Keys, and you should see a link to a help page. Done? Good! That was the most difficult part!&lt;br /&gt;
&lt;br /&gt;
4. If you want, you can set up [[Travis integration]] with your GitHub repository so that when you push your code, Travis will automatically run a suite of tests for you against your changes. This way you can quickly catch issues without having to set up a testing environment locally (and before you share your code with other Moodle developers!). Another option to automate the execution of the Moodle test suite is to setup [[Github actions integration]].&lt;br /&gt;
&lt;br /&gt;
== Setting-up the local repository at your computer  ==&lt;br /&gt;
&lt;br /&gt;
Create a local clone repository of your Github repository. In a terminal:&lt;br /&gt;
&lt;br /&gt;
    git clone git://github.com/YOUR_GITHUB_USERNAME/moodle.git LOCALDIR&lt;br /&gt;
&lt;br /&gt;
    (or:  git clone git@github.com:YOUR_GITHUB_USERNAME/moodle.git LOCALDIR)&lt;br /&gt;
&lt;br /&gt;
This command does several jobs for you. It creates a new folder, initializes an empty Git repository in it, sets your Github repository as the remote repository called &#039;origin&#039; and makes a local checkout of the branch &#039;master&#039; from it. The important point to remember now is that your Github repository is aliased as &#039;origin&#039; for your local clone.&lt;br /&gt;
&lt;br /&gt;
Note that the format of the URL here is important. In the first example, the URL starts &amp;quot;git://github.com&amp;quot; and this will give read-only access to the repository at github.com. If you use this URL, the &amp;quot;git push origin&amp;quot; command that appears later in this document will not work. Therefore, if you want to be able to update the &amp;quot;origin&amp;quot; repository, you should use the URL that starts &amp;quot;git@github.com&amp;quot;, i.e. the second of the two &amp;quot;git clone&amp;quot; commands given above. This will give you read and write access to the repository on github.com.&lt;br /&gt;
&lt;br /&gt;
== Keeping your public repository up-to-date ==&lt;br /&gt;
&lt;br /&gt;
[[image:git-sync-github.png|right|thumb|400px|Fetching changes from upstream and pushing them to github]]&lt;br /&gt;
Your fork at Github is not updated automatically. To keep it synced with the upstream Moodle repository, you have to fetch the recent changes from the official moodle.git and push them to your public repository. To avoid problems with this it is strongly recommended that you never modify the standard Moodle branches. &#039;&#039;Remember: never commit directly into master and MOODLE_xx_STABLE branches.&#039;&#039; In other words, always create topic branches to work on. In Gitspeak, the master branch and MOODLE_xx_STABLE branches should be always fast-forwardable.&lt;br /&gt;
&lt;br /&gt;
To keep your public repository up-to-date, we will register remote repository git://git.moodle.org/moodle.git under &#039;upstream&#039; alias. Then we create a script to be run regularly that fetches changes from the upstream repository and pushes them to your public repository. Note that this procedure will not affect your local working directory.&lt;br /&gt;
&lt;br /&gt;
To register the upstream remote:&lt;br /&gt;
&lt;br /&gt;
    cd moodle&lt;br /&gt;
    git remote add upstream git://git.moodle.org/moodle.git&lt;br /&gt;
&lt;br /&gt;
The following commands can be used to keep the standard Moodle branches at your Github repository synced with the upstream repository. You may wish to store them in a script so that you can run it every week after the upstream repository is updated.&lt;br /&gt;
&lt;br /&gt;
    #!/bin/bash&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    for BRANCH in MOODLE_{19..39}_STABLE MOODLE_{310..311}_STABLE master; do&lt;br /&gt;
        git push origin refs/remotes/upstream/$BRANCH:refs/heads/$BRANCH&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
The git-fetch command does not modify your current working dir (your checkout). It just downloads all recent changes from a remote repository and stores them into so called remote-tracking branches. The git-push command takes these remote-tracking branches from upstream and pushes them to Github under the same name. Understanding this fully requires a bit knowledge of Git internals - see gitrevisions(7) man page.&lt;br /&gt;
&lt;br /&gt;
Note there is no need to switch the local branch during this. You can even execute this via cron at your machine. Just note that the upstream repository updates typically just once a week.&lt;br /&gt;
&lt;br /&gt;
=== New branches ===&lt;br /&gt;
&lt;br /&gt;
Occasionally, moodle.org will create a new branch that does not exist in your public (e.g. Github.com) repository. If you try to push this new branch, you will see an error such as the following:&lt;br /&gt;
&lt;br /&gt;
    error: unable to push to unqualified destination: MOODLE_99_STABLE&lt;br /&gt;
    The destination refspec neither matches an existing ref on the remote&lt;br /&gt;
    nor begins with refs/, and we are unable to guess a prefix based on the source ref.&lt;br /&gt;
    error: failed to push some refs to &#039;git@github.com:YOUR_GITHUB_USERNAME/moodle.git&#039;&lt;br /&gt;
&lt;br /&gt;
In the above example, &amp;quot;MOODLE_99_STABLE&amp;quot;, is the name of the new branch that does not exist in your public repository. To fix the error, you need to create the new branch on your public repository, using the following commands, replacing &amp;quot;MOODLE_99_STABLE&amp;quot; with the name of the new branch you wish to create:&lt;br /&gt;
&lt;br /&gt;
    git checkout MOODLE_99_STABLE&lt;br /&gt;
    git push origin MOODLE_99_STABLE:MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
The above code will create a new copy of the &amp;quot;MOODLE_99_STABLE&amp;quot; branch in your local repository. If you do not need to keep a local copy of the new branch - and probably you do not need it, you then can remove it from your local repository as follows:&lt;br /&gt;
&lt;br /&gt;
    git checkout master&lt;br /&gt;
    git branch -D MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
== Preparing a patch ==&lt;br /&gt;
&lt;br /&gt;
As said earlier at this page, you never work on standard Moodle branches directly. Every time you are going to edit something, switch to a local branch. Fork the local branch off the standard branch you think it should be merged to. So if you are working on a patch for 1.9 or 2.0, fork the branch off MOODLE_19_STABLE or MOODLE_20_STABLE, respectively. Patches for the next [[Moodle versions|major version]] should be based on the master branch.&lt;br /&gt;
&lt;br /&gt;
    git checkout -b MDL-xxxxx-master_brief_name origin/master&lt;br /&gt;
&lt;br /&gt;
Note that if you forget to specify the starting point, the branch is based on the currently checked-out branch. It may not be what you want. It is recommended to always specify the starting point.&lt;br /&gt;
&lt;br /&gt;
To check the current branch, run&lt;br /&gt;
&lt;br /&gt;
    git branch&lt;br /&gt;
&lt;br /&gt;
The current branch is highlighted.&lt;br /&gt;
&lt;br /&gt;
Now go and fix the issue with your favorite IDE. Check the status of the files, view the change to be committed and finally commit the change:&lt;br /&gt;
&lt;br /&gt;
    vim filename.php&lt;br /&gt;
    git status&lt;br /&gt;
    git diff&lt;br /&gt;
    git commit -a&lt;br /&gt;
&lt;br /&gt;
For the commit message, please do respect the guidelines given on in the article [[Coding style#Git_commits|Coding_style]].&lt;br /&gt;
&lt;br /&gt;
Note that this is safe as the commit is recorded just locally, nothing is sent to any server yet (as it would in CVS). To see history of the commits, use&lt;br /&gt;
&lt;br /&gt;
    git log&lt;br /&gt;
&lt;br /&gt;
Once your local branch contains the change (note that it may consists of several patches) and you are happy with it, publish the branch at your public repository:&lt;br /&gt;
&lt;br /&gt;
    git push origin MDL-xxxxx-master_brief_name&lt;br /&gt;
&lt;br /&gt;
Now as your branch is published, you can ask Moodle core developers to review it and eventually integrate it into the standard Moodle repository.&lt;br /&gt;
&lt;br /&gt;
=== Changing commit message, reordering and squashing commits ===&lt;br /&gt;
&lt;br /&gt;
It often happens that you made a mistake in your patch or in the commit message and helpful CiBot pointed it out for you. You can &amp;quot;rewrite the history&amp;quot; and change the existing commits.&lt;br /&gt;
&lt;br /&gt;
Option 1. Reset all the changes in the branch and commit again. &lt;br /&gt;
&lt;br /&gt;
    git reset --mixed origin/master&lt;br /&gt;
&lt;br /&gt;
Now all your changes are still present but all commits on top of &amp;quot;master&amp;quot; branch are gone. You can create a new commit&lt;br /&gt;
&lt;br /&gt;
Option 2. Discover &#039;&#039;&#039;git rebase --interactive&#039;&#039;&#039; - this is a powerful tool to change the sequence of commit, change the commit messages, squash commits, etc. We will not cover it here, there are many articles in the Internet about it, for example: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History.&lt;br /&gt;
&lt;br /&gt;
Whatever option you chose, you have &amp;quot;rewritten the history&amp;quot; and you can not simply push the changes to github again because they would need to overwrite the commits that were already pushed. If you try &amp;quot;git push MDL-xxxxx-master_brief_name&amp;quot; you will get an error message suggesting you to force push. &lt;br /&gt;
To force push the changed commits use:&lt;br /&gt;
&lt;br /&gt;
    git push -f origin MDL-xxxxx-master_brief_name&lt;br /&gt;
&lt;br /&gt;
If an error occurs because you are still using the git protocol (read only), use this command : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin https://github.com/&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
A prompt will ask for your credentials, if you previously setup your SSH public key you can also use this one : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin git@github.com:&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
=== Checking if a branch has already been merged ===&lt;br /&gt;
&lt;br /&gt;
After some time contributing to Moodle you would have a lot of branches both in your local repository and in your public repository. To prune their list and delete those that were accepted by upstream, use the following&lt;br /&gt;
&lt;br /&gt;
    git fetch upstream                                      (1)&lt;br /&gt;
    git branch --merged upstream/master                     (2)&lt;br /&gt;
    git branch --merged upstream/MOODLE_20_STABLE           (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) fetches the changes from your upstream repository at git.moodle.org (remember that git-fetch does not modify your working dir so it is safe to run it whenever). Command (2) and (3) print all branches that are merged into the upstream master branch and MOODLE_20_STABLE branch, respectively. To delete these local branches, use&lt;br /&gt;
&lt;br /&gt;
    git branch -d MDL-xxxxx-master_accepted_branch&lt;br /&gt;
&lt;br /&gt;
The similar approach can be used to check the branches published at your origin repository at github.com&lt;br /&gt;
&lt;br /&gt;
    git fetch origin                                        (1)&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    git branch -r --merged upstream/master                  (2)&lt;br /&gt;
    git branch -r --merged upstream/MOODLE_20_STABLE        (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) makes sure that you have all your branches from github.com recorded as the remote tracking branch locally. Commands (2) and (3) work the same as in the previous example but they list remote tracking branches only ([http://www.kernel.org/pub/software/scm/git/docs/git-branch.html see -r param]). To delete a branch at github.com, use&lt;br /&gt;
&lt;br /&gt;
    git push origin :MDL-xxxxx-master_branch_to_delete&lt;br /&gt;
&lt;br /&gt;
This syntax may look weird to you. However it is pretty logical. The general syntax of the git-push command is&lt;br /&gt;
&lt;br /&gt;
    git push &amp;lt;repository&amp;gt; &amp;lt;source ref&amp;gt;:&amp;lt;target ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so deleting a remote branch can be understood as pushing an &amp;quot;empty (null) reference&amp;quot; to it.&lt;br /&gt;
&lt;br /&gt;
== Peer-reviewing someone else&#039;s code ==&lt;br /&gt;
&lt;br /&gt;
To review a branch that someone else pushed into their public repository, you do not need to register a new remote (unless you work with such repository frequently, of course). Let us imagine your friend Alice pushed a work-in-progress branch called &#039;wip-feature&#039; into her Github repository and asked you to review it. You need to know the read-only address of the repository and the name of the branch.&lt;br /&gt;
&lt;br /&gt;
    git fetch git://github.com/alice/moodle.git wip-feature&lt;br /&gt;
&lt;br /&gt;
This will download all required data and will keep the pointer to the tip of the wip-feature branch in a local symbolic reference FETCH_HEAD. To see what&#039;s there on that branch, use&lt;br /&gt;
&lt;br /&gt;
    git log -p FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see how a particular file looks at Alice&#039;s branch&lt;br /&gt;
&lt;br /&gt;
    git show FETCH_HEAD:admin/blocks.php&lt;br /&gt;
&lt;br /&gt;
To create a new local branch called &#039;alice-wip-feature&#039; containing the work by Alice, use&lt;br /&gt;
&lt;br /&gt;
    git checkout -b alice-wip-feature FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To merge Alice&#039;s work into your current branch:&lt;br /&gt;
&lt;br /&gt;
    git merge FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see what would be merged into the current branch without actually modifying anything:&lt;br /&gt;
&lt;br /&gt;
    git diff ...FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
Once you are all set and reviewing code, this [[Peer_reviewing_checklist|checklist]] should prove to be useful.&lt;br /&gt;
&lt;br /&gt;
== Rebasing a branch ==&lt;br /&gt;
&lt;br /&gt;
Rebasing is a process when you cut off the branch from its current start point and transplant it to another point. Let us assume the following history exists:&lt;br /&gt;
&lt;br /&gt;
          A---B---C topic&lt;br /&gt;
         /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
From this point, the result of the command:&lt;br /&gt;
&lt;br /&gt;
    git rebase master topic&lt;br /&gt;
&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
                  A&#039;--B&#039;--C&#039; topic&lt;br /&gt;
                 /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
and would end with &#039;topic&#039; being your current branch.&lt;br /&gt;
&lt;br /&gt;
You may be asked to rebase your branch submitted for the integration if the submitted branch was based on an outdated commit. The typical case is if you create a new branch as a fork off the upstream master branch on Tuesday. Then on Wednesday, the upstream master branch grows as all changes from the last integration cycle are merged to it. To make diff easy on Github for next weekly pull request review, you want to rebase your branch against the updated master.&lt;br /&gt;
&lt;br /&gt;
    git rebase master MDL-xxxxx-master_topic_branch&lt;br /&gt;
&lt;br /&gt;
Note that rebasing effectively rewrites the history of the branch. &#039;&#039;&#039;Do not rebase the branch if there is a chance that somebody has already forked it and based their own branch on it.&#039;&#039;&#039; For this reason, many Git tutorials discourage from rebasing any branch that has been published. However in Moodle, all branches submitted for integration are potential subject of rebase (even though we try to not to do it often) and you should not base your own branches on them.&lt;br /&gt;
&lt;br /&gt;
=== Conflicts during rebase ===&lt;br /&gt;
&lt;br /&gt;
During the rebase procedure, conflicts may appear. git-status commands reports the conflicted files. Explore them carefully and fix them in your editor (like you would do with CVS). Then add the files with &#039;git add&#039; command and continue.&lt;br /&gt;
&lt;br /&gt;
    vim conflicted.php&lt;br /&gt;
    git add conflicted.php&lt;br /&gt;
    git rebase --continue&lt;br /&gt;
&lt;br /&gt;
== Applying changes from one branch to another ==&lt;br /&gt;
&lt;br /&gt;
Most bugs are fixed at a stable branch (like MOODLE_20_STABLE) and the fix must be prepared for other branches, too (like MOODLE_21_STABLE and the main development branch - master). In Moodle, we do not merge stable branches into the master one. So usually the contributor prepares at least two branches - with the fix for the stable branch(es) and with the fix for the master branch.&lt;br /&gt;
&lt;br /&gt;
If you have a patch prepared on a local branch (let us say MDL-xxxxx-20_brief_name), it is possible to re-apply it to another branch.&lt;br /&gt;
&lt;br /&gt;
=== Cherry-picking a single commit ===&lt;br /&gt;
&lt;br /&gt;
Let us have two local Git repositories ~/public_html/moodle21 containing local installation of Moodle 2.1 and ~/public_html/moodledev with the local installation of most recent development version of Moodle. They both use your public repository at github.com as the origin. You have a branch in moodle21 called MDL-xxxxx-21_topic that was forked off MOODLE_21_STABLE. It contains one commit. Now you want to re-apply this commit to a branch MDL-xxxxx-master_topic in moodledev.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxxx-master_topic origin/master    (1)&lt;br /&gt;
    git fetch ../moodle21 MDL-xxxxx-21_topic                (2)&lt;br /&gt;
    git cherry-pick FETCH_HEAD                              (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) creates new local branch forked off the master. The command (2) fetches all data needed to re-apply the topic branch and stores the pointer to the tip of that branch to FETCH_HEAD symbolic reference. The command (3) picks the tip of the branch (the top-most commit on it) and tries to apply it on the current branch.&lt;br /&gt;
There is also a variant of the cherry-pick command that supports multiple commits, shortly (see its man page for details): &amp;lt;code bash&amp;gt;$ git cherry-pick A^..B&amp;lt;/code&amp;gt; if you want to include from A - see &#039;&#039;&#039;^&#039;&#039;&#039; - to B, A should be older than B. We will use another approach for cherry-picking multiple commits.&lt;br /&gt;
&lt;br /&gt;
=== Applying a set of patches ===&lt;br /&gt;
&lt;br /&gt;
If the branch MDL-xxxxx-21_topic from the previous example consists of several commits, it may be easier to use git-format-patch and git-am combo to re-apply the whole set of patches (aka patchset). Firstly you will export all commits from the topic branch to files.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodle21&lt;br /&gt;
    mkdir .patches&lt;br /&gt;
    git format-patch -o .patches MOODLE_21_STABLE..MDL-xxxxx-21_topic         (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) takes all commits from the topic branch that are not in MOODLE_21_STABLE and exports them one by one to the output directory .patches. Look at the generated files. They contain the patch itself (in diff format) and additional information about the commit. You could eg send these files by email to a friend of yours for peer-review. We will use them in another repository.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxxx-master_topic origin/master&lt;br /&gt;
    git am -3 ../moodle21/.patches/*                        (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) applies all the files from the .patches directory. When a patch does not apply cleanly, the command tries fall back on 3-way merge (see the -3 parameter). If conflicts occur during the procedure, you can either deal with them and then use `git am --continue` or abort the whole procedure with `git am --abort`.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Git tips]]&lt;br /&gt;
&lt;br /&gt;
; Moodle forum discussions&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=168094 GIT help needed]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=165236 Best way to manage CONTRIB code with GIT]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167063 Handy Git tip for tracking 3rd-party modules and plugins]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167730 Moodle Git repositories]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=183409 Git help!! I don&#039;t understand rebase enough...]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=217617 add MOODLE_24_STABLE to github.com repository]&lt;br /&gt;
&lt;br /&gt;
; External resources &lt;br /&gt;
* [https://mirrors.edge.kernel.org/pub/software/scm/git/docs/giteveryday.html Everyday GIT With 20 Commands Or So]&lt;br /&gt;
* [https://git-scm.com/book/en/v2 &#039;Pro Git&#039; complete book]&lt;br /&gt;
* [http://vimeo.com/14629850 Getting git by Scott Chacon] - an recording of an excellent 1-hour presentation that introducing git, including a simple introduction to what is going on under the hood.&lt;br /&gt;
* [http://tjhunt.blogspot.co.uk/2012/03/fixing-bug-in-moodle-core-mechanics.html Tim Hunt&#039;s blog: Fixing a bug in Moodle core: the mechanics]&lt;br /&gt;
* [https://github.com/k88hudson/git-flight-rules/blob/master/README.md#flight-rules-for-git Flight rules for Git]&lt;br /&gt;
&lt;br /&gt;
[[Category:Git]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発者用Git]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.11_release_notes&amp;diff=58236</id>
		<title>Moodle 3.11 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.11_release_notes&amp;diff=58236"/>
		<updated>2021-01-25T14:44:09Z</updated>

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

		<summary type="html">&lt;p&gt;Scaroodle: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;Travis [https://mailchi.mp/3d439eeb1098/travis-ciorg-is-moving-to-travis-cicom has announced] that &#039;&#039;&#039;travis-ci.org will be closed down completely on December 31st 2020&#039;&#039;&#039;, with travis-ci.com becoming the unified place for all projects. More information can be found at:&lt;br /&gt;
* [https://docs.travis-ci.com/user/migrate/open-source-repository-migration Migrating repositories to travis-ci.com]&lt;br /&gt;
* Moodle Tracker: MDLSITE-6246&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;note&amp;quot;&amp;gt;Travis [https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing has announced], November 2, 2020, that &#039;&#039;&#039;travis-ci.com won&#039;t be (unlimitedly) free anymore&#039;&#039;&#039;, with everybody getting some credits (processing time) once and, after using them, you must change to some of their (paid) plans. Few weeks later, November 24, 2020, [https://blog.travis-ci.com/oss-announcement they have published an update] specifically for Open Source. There, they recommend to contact them &#039;&#039;&amp;quot;for anything relating with your open source account&amp;quot;&#039;&#039;. Up to you!&lt;br /&gt;
More information can be found at:&lt;br /&gt;
* Moodle Tracker: MDL-70265&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Moodle core ==&lt;br /&gt;
&lt;br /&gt;
=== Background ===&lt;br /&gt;
&lt;br /&gt;
Moodle is regularly tested against a matrix of Databases, PHP Versions, and operating systems, however many developers do not have the resources available to run on many of these combinations before pushing an issue for integration as they are time-consuming to both set up and to run.&lt;br /&gt;
&lt;br /&gt;
There are many Continuous Integration tools available to developers, and Travis-CI is just one of those available to the Open Source community.&lt;br /&gt;
&lt;br /&gt;
Since version 3.0, Moodle includes a Travis configuration file in its repository. This configuration file configures and controls a Travis build across a matrix of testing environments. This allows developers pushing patches to Moodle to have their code unit tested before it reaches integration. The hope is that the availability of this integration should reduce the number of unit test failures seen during Integration.&lt;br /&gt;
&lt;br /&gt;
Note: Moodle HQ uses the Jenkins CI platform internally and this should be seen as the canonical CI server for Moodle. The Travis integration provided is to provide early warning to developers of any issues with their code.&lt;br /&gt;
&lt;br /&gt;
=== Usage ===&lt;br /&gt;
&lt;br /&gt;
Travis-CI is available and is usually configured to run automatically when pushing code, but it must be configured before first use.&lt;br /&gt;
&lt;br /&gt;
For the purpose of this documentation, it is assumed that you are pushing to a public Moodle repository on GitHub. Other integrations are supported, but the service available from Travis is only available to public repositories.&lt;br /&gt;
&lt;br /&gt;
=== Setup ===&lt;br /&gt;
&lt;br /&gt;
# [https://travis-ci.com/auth Sign in to Travis CI] using your GitHub account&lt;br /&gt;
# Once you’re signed in, and the initial synchronisation of your GitHub repositories has completed, go to your [https://travis-ci.com/profile profile page]&lt;br /&gt;
# Enable Travis CI for your clone of the Moodle repository [[File:moodle-travis-enable.png]]&lt;br /&gt;
# Click on the cog icon to configure the Integration&lt;br /&gt;
# Ensure that &amp;quot;Build pushed branches&amp;quot; is enabled [[File:moodle-travis-settings-2020.png]]&lt;br /&gt;
# Email notifications will be sent by default to the committer and the commit author. If you want to turn off email notifications for this repository, you can define an environment variable with name MOODLE_EMAIL and &amp;quot;no&amp;quot; as value.&lt;br /&gt;
# By default, the following jobs will be executed for each branch sent to github:&lt;br /&gt;
## GRUNT: 1 job that will check that all your javascript and scss has been properly built (see [[Grunt]]) and is part of the patch.&lt;br /&gt;
## CITESTS: 1 job that will perform a lightweight linting of your branch.&lt;br /&gt;
## PHPUNIT: 1 job that will run all the unit tests on your branch (using the lowest PHP version supported by the branch and PostgreSQL as database).&lt;br /&gt;
# If you want to change those defaults, you can use the following environment variables:&lt;br /&gt;
## MOODLE_DATABASE: With value &amp;quot;mysqli&amp;quot; to switch your runs to that database. With value &amp;quot;all&amp;quot; to run both PostgreSQL and MySQL unit tests.&lt;br /&gt;
## MOODLE_PHP: With value &amp;quot;all&amp;quot;, to run the unit tests both with the lowest and the highest PHP versions supported by the branch.&lt;br /&gt;
Note that adding more jobs will increase the time needed (and the credits consumed) for processing each branch, so be careful picking your fav configuration.&lt;br /&gt;
[[File:environment_variables.png|Define an environment variable]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== How do I start a build? ===&lt;br /&gt;
&lt;br /&gt;
It won&#039;t build immediately after setup. Builds start automatically when you push a change.&lt;br /&gt;
&lt;br /&gt;
== Moodle plugins ==&lt;br /&gt;
&lt;br /&gt;
See [https://moodlehq.github.io/moodle-plugin-ci/ Moodle Plugin CI repository] for setup instructions.&lt;br /&gt;
&lt;br /&gt;
Related discussions:&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=323384 Adding Travis CI support into your plugin]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=389744 Recent Travis-CI issues with plugins]&lt;br /&gt;
&lt;br /&gt;
=== Ignoring files and folders ===&lt;br /&gt;
&lt;br /&gt;
For some of the code analysis tools, it is important to ignore some files within the plugin because they might not be fixable, like a third party library. The all code analysis commands in this project ignore files and directories listed in the thirdpartylibs.xml plugin file. See https://docs.moodle.org/dev/Plugin_files#thirdpartylibs.xml for more info.&lt;br /&gt;
&lt;br /&gt;
==== Ignoring files ====&lt;br /&gt;
&lt;br /&gt;
Specifically for the codechecker command, you can ignore a single line, a section of a file or the whole file by using specific PHP comments. For details see this [[CodeSniffer]] wiki page.&lt;br /&gt;
In addition, you can ignore additional files by defining IGNORE_PATHS and/or IGNORE_NAMES environment variables in your .travis.yml file. These environment variables wont work for Grunt tasks, but will for everything else. Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
env:&lt;br /&gt;
 global:&lt;br /&gt;
  - MOODLE_BRANCH=MOODLE_35_STABLE&lt;br /&gt;
  - IGNORE_PATHS=vendor/widget,javascript/min-lib.js&lt;br /&gt;
  - IGNORE_NAMES=*-m.js,bad_lib.php&lt;br /&gt;
 matrix:&lt;br /&gt;
  - DB=pgsql&lt;br /&gt;
  - DB=mysqli&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Both environment variables take a CSV value. For IGNORE_PATHS, it takes relative file paths to ignore. File paths can be a simple string like foo/bar or a regular expression like /^foo\/bar/. For IGNORE_NAMES, it takes file names to ignore. File names can be a simple string like foo.php, a glob like *.php or a regular expression like /\.php$/.&lt;br /&gt;
&lt;br /&gt;
If you need to specify ignore paths for a specific command, then you can define additional environment variables. The variable names are the same as above, but prefixed with COMMANDNAME_. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
env:&lt;br /&gt;
 global:&lt;br /&gt;
  - MOODLE_BRANCH=MOODLE_35_STABLE&lt;br /&gt;
  - IGNORE_PATHS=vendor/widget,javascript/min-lib.js&lt;br /&gt;
  - IGNORE_NAMES=*-m.js,bad_lib.php&lt;br /&gt;
  - PHPUNIT_IGNORE_PATHS=$IGNORE_PATHS,cli&lt;br /&gt;
 matrix:&lt;br /&gt;
  - DB=pgsql&lt;br /&gt;
  - DB=mysqli&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In the above example, we are adding the cli path to our ignore paths for the PHPUnit command (this is also how you can ignore files for code coverage). Please note that this is a complete override and there is no merging with IGNORE_PATHS and IGNORE_NAMES. So, in the above, the PHPUnit command would not ignore the file names defined in IGNORE_NAMES.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Talk:Travis Integration]] for previous Travis dev docs&lt;br /&gt;
&lt;br /&gt;
[[Category:Developer tools]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56733</id>
		<title>Javascript Modules</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Javascript_Modules&amp;diff=56733"/>
		<updated>2019-12-12T08:24:10Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Adding a reference to examples of JS issues starting from 3.8&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.9}}&lt;br /&gt;
&lt;br /&gt;
= Javascript Modules =&lt;br /&gt;
&lt;br /&gt;
== What is a Javascript module and why do I care? ==&lt;br /&gt;
&lt;br /&gt;
A Javascript module is nothing more than a collection of Javascript code that can be used (reliably) from other pieces of Javascript. &lt;br /&gt;
&lt;br /&gt;
== Why should I package my code as a module? ==&lt;br /&gt;
&lt;br /&gt;
By packaging your code as a module you break your code up into smaller reusable pieces. This is good because:&lt;br /&gt;
&lt;br /&gt;
a) Each smaller piece is simpler to understand / debug&lt;br /&gt;
&lt;br /&gt;
b) Each smaller piece is simpler to test&lt;br /&gt;
&lt;br /&gt;
c) You can re-use common code instead of duplicating it&lt;br /&gt;
&lt;br /&gt;
= How do I write a Javascript module in Moodle? =&lt;br /&gt;
&lt;br /&gt;
Since version 2.9, Moodle supports Javascript modules written using the Asynchronous Module Definition ([https://github.com/amdjs/amdjs-api/wiki/AMD AMD]) API. This is a standard API for creating Javascript modules and you will find many useful third party libraries that are already using this format. &lt;br /&gt;
&lt;br /&gt;
To edit or create an AMD module in Moodle you need to do a couple of things. &lt;br /&gt;
&lt;br /&gt;
Since version 3.8, Moodle supports [https://github.com/lukehoban/es6features#readme ECMAScript 2015 features] (aka ES6) in a cross browser compatible way thanks to [https://babeljs.io/ Babel JS]. In order to achieve the compatibility with older browsers Babel will compile the newer ES6 features back into ES5 Javascript. Unfortunately this means that in order for your Javascript changes to show in the browser they must be compiled by running Grunt, even with the cachejs config setting set to false (i.e. &amp;quot;Development mode&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
== Install grunt ==&lt;br /&gt;
&lt;br /&gt;
The AMD modules in Moodle must be processed by some build tools before they will be visible to your web browser. We use &amp;quot;[[grunt]]&amp;quot; as a build tool to wrap our different processes. Grunt is a build tool written in Javascript that runs in the &amp;quot;[http://nodejs.org/ nodejs]&amp;quot; environment.&lt;br /&gt;
&lt;br /&gt;
This means you first have to &#039;&#039;&#039;install nodejs&#039;&#039;&#039; - and its package manager [https://www.npmjs.com/ npm]. The details of how to install those packages will vary by operating system, but on Linux it&#039;s probably similar to &amp;quot;sudo apt-get install nodejs npm&amp;quot;. There are downloadable packages for other operating systems here: http://nodejs.org/download/. Moodle currently requires node {{NodeJSVersion}}.&lt;br /&gt;
&lt;br /&gt;
Once this is done, you can &#039;&#039;&#039;run the command&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
 npm install&lt;br /&gt;
 npm install -g grunt-cli&lt;br /&gt;
&lt;br /&gt;
from the top of the Moodle directory to install all of the required tools. (You may need extra permissions to use the -g option.)&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v2.9 to v3.7)  ==&lt;br /&gt;
&lt;br /&gt;
To avoid having to constantly run grunt, make sure you set the following in your config.php&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Moodle will now run your module from the amd/src module. Don&#039;t forget to switch this off and run &#039;grunt&#039; before deploying the new version!&lt;br /&gt;
&lt;br /&gt;
In this mode - if you get a strange message in your javascript console like &amp;quot;No define call for core/first&amp;quot; it means you have a syntax error in the javascript you are developing. &lt;br /&gt;
Or, &amp;quot;No define call for theme_XXX/loader&amp;quot; as you are probably missing the &#039;src&#039; folder with relevant JS files. which might happen when you turn debugging ON on a theme that was bought, without &#039;src&#039; folder :-(&lt;br /&gt;
&lt;br /&gt;
== Development mode (Moodle v3.8 and above)  ==&lt;br /&gt;
&lt;br /&gt;
All Javascript code is now compiled using Babel which means Moodle will only ever serve minified Javascript to the browser, even in development mode. However in development mode Moodle will also send the browser the corresponding source map files for each of the Javascript modules. The source map files will tell the browser how to map the minified source code back to the unminified original source code so that the original source files will be displayed in the sources section of the browser&#039;s development tools.&lt;br /&gt;
&lt;br /&gt;
While in development mode each of the Javascript modules will appear in the browser&#039;s source tree as separate modules (no more giant first.js file!) and they will also be loaded with individual network requests (this is a compromise we had to make thanks to some browser bugs with source map files).&lt;br /&gt;
&lt;br /&gt;
To enable development mode set the &#039;&#039;&#039;cachejs&#039;&#039;&#039; config value to &#039;&#039;&#039;false&#039;&#039;&#039; in the admin settings or directly in your config.php file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Prevent JS caching&lt;br /&gt;
$CFG-&amp;gt;cachejs = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since all Javascript must now be compiled you must run Grunt in order for you changes to appear in the browser. However rather than running Grunt manually each time on either the whole project or each file you modified, it is recommended that you just run the &#039;&#039;&#039;grunt watch&#039;&#039;&#039; task at the root of your Moodle directory. The grunt watch task will listen for changes to the Javascript files in the Moodle directory and will automatically lint and compile only the file that is changed after each change is detected. This removes the need to manually run grunt after each change.&lt;br /&gt;
&lt;br /&gt;
== Running grunt ==&lt;br /&gt;
&lt;br /&gt;
You can run grunt in your plugin&#039;s &#039;amd&#039; directory and it will only operate on your modules. If you&#039;re having problems or just want to check your work it is worth running for the &#039;lint&#039; feature. This can find basic problems. This sub-directory support wont work on Windows unfortunately but there is an alternative: Run grunt from the top directory with the --root=path/to/dir to limit execution to a sub-directory.&lt;br /&gt;
&lt;br /&gt;
See [[Grunt#Running_grunt]] for more details of specific grunt commands which can be used.&lt;br /&gt;
&lt;br /&gt;
If you get the error message&lt;br /&gt;
&lt;br /&gt;
 /usr/bin/env: node: No such file or directory&lt;br /&gt;
&lt;br /&gt;
Then see the thread https://github.com/nodejs/node-v0.x-archive/issues/3911&lt;br /&gt;
&lt;br /&gt;
On Ubuntu 14.04 this fixed it for me:&lt;br /&gt;
&lt;br /&gt;
 sudo ln -fs /usr/bin/nodejs /usr/local/bin/node&lt;br /&gt;
&lt;br /&gt;
Note: Once you have run grunt and built your code, you will then need to purge Moodle caches otherwise the changes made to your minified files may not be picked up by Moodle.&lt;br /&gt;
&lt;br /&gt;
== ES6 Modules (Moodle v3.8 and above) ==&lt;br /&gt;
&lt;br /&gt;
In addition to AMD module syntax Moodle now supports the [https://github.com/lukehoban/es6features#modules ES6 syntax] for writing Javascript modules. All modules (defined using either syntax) are compatible with one another. Behind the scenes the ES6 module syntax is converted into an AMD syntax as part of the Babel compiling process.&lt;br /&gt;
&lt;br /&gt;
=== Export default ===&lt;br /&gt;
There is one slight difference between the ES6 definition for exporting modules and the RequireJS (AMD) definition.&lt;br /&gt;
&lt;br /&gt;
ES6 allows you to export a “default” value which is actually no different to exporting a named value where the name is “default”. Unfortunately, RequireJS allows for unnamed default exports (e.g. you can do &amp;quot;return SomeClass;&amp;quot;) which can be imported by just requiring them in other AMD modules.&lt;br /&gt;
&lt;br /&gt;
That’s a bit confusing, get to the point! Well, it basically means that in Moodle you won’t be able to write an ES6 module that exports both a default and named exports, e.g. &amp;quot;export default function() {...}&amp;quot; and &amp;quot;export const FOO = &#039;bar&#039;&amp;quot; in the same module. The export default will simply override all other exports in that module.&lt;br /&gt;
&lt;br /&gt;
=== Inline Javascript ===&lt;br /&gt;
Another important note is that ES6 support is only for stand alone Javascript files because it relies on the compilation from Babel and Grunt. That means any inline Javascript (either in PHP or in Mustache templates) won&#039;t support the ES6 features. Instead it would be best to keep the inline Javascript as minimal as possible and only use it to load a stand alone Javascript module.&lt;br /&gt;
&lt;br /&gt;
== Minimum (getting started) module for plugins ==&lt;br /&gt;
&lt;br /&gt;
This shows the absolute minimum module you need to get started adding modules to your plugins. It&#039;s actually quite simple...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Put this file in path/to/plugin/amd/src&lt;br /&gt;
// You can call it anything you like&lt;br /&gt;
&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
    return {&lt;br /&gt;
        init: function() {&lt;br /&gt;
&lt;br /&gt;
            // Put whatever you like here. $ is available&lt;br /&gt;
            // to you as normal.&lt;br /&gt;
            $(&amp;quot;.someclass&amp;quot;).change(function() {&lt;br /&gt;
                alert(&amp;quot;It changed!!&amp;quot;);&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;
This code passes the jquery module into our function (parameter $). There are a number of other useful modules available in Moodle, some of which you&#039;ll probably need in a practical application. See [[Useful_core_Javascript_modules]]. Simply list them in both the define() first parameter and the function callback. E.g.,&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    define([&#039;jquery&#039;, &#039;core/str&#039;, &#039;core/ajax&#039;], function($, str, ajax) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The idea here is that we will run the &#039;init&#039; function from our (PHP) code to set things up. This is called from PHP like this...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;frankenstyle_path/your_js_filename&#039;, &#039;init&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to supply the complete &#039;[[Frankenstyle]]&#039; path. The .js is not needed. &lt;br /&gt;
&lt;br /&gt;
js_call_amd takes a third parameter which is an &#039;&#039;array&#039;&#039; of parameters. These will translate to individual parameters in the &#039;init&#039; function call. For example...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $PAGE-&amp;gt;requires-&amp;gt;js_call_amd(&#039;block_iomad_company_admin/department_select&#039;, &#039;init&#039;, array($first, $last));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...calls&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
    return {&lt;br /&gt;
        init: function(first, last) {&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A more comprehensive explanation follows...&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Hello World&amp;quot; I am a Javascript Module ==&lt;br /&gt;
Lets now create a simple Javascript module so we can see how to lay things out. &lt;br /&gt;
&lt;br /&gt;
Each Javascript module is contained in a single source file in the &amp;lt;componentdir&amp;gt;/amd/src folder. The final name of the module is taken from the file name and the component name. E.g. block_overview/amd/src/helloworld.js would be a module named &amp;quot;block_overview/helloworld&amp;quot;. the name of the module is important when you want to call it from somewhere else in the code. &lt;br /&gt;
&lt;br /&gt;
After running grunt - the minified Javascript files are stored in the &amp;lt;componentdir&amp;gt;/amd/build folder. The javascript files are renamed to show that they are minified (helloworld.js becomes helloworld.min.js). &lt;br /&gt;
&lt;br /&gt;
Don&#039;t forget to add the built files (the ones in amd/build) to your git commits, or in production no-one will see your changes. &lt;br /&gt;
&lt;br /&gt;
Lets create a simple module now:&lt;br /&gt;
&lt;br /&gt;
blocks/overview/amd/src/helloworld.js&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// Standard license block omitted.&lt;br /&gt;
/*&lt;br /&gt;
 * @package    block_overview&lt;br /&gt;
 * @copyright  2015 Someone cool&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 /**&lt;br /&gt;
  * @module block_overview/helloworld&lt;br /&gt;
  */&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&lt;br /&gt;
     /** &lt;br /&gt;
      * Give me blue.&lt;br /&gt;
      * @access private&lt;br /&gt;
      * @return {string}&lt;br /&gt;
      */&lt;br /&gt;
     var makeItBlue = function() {&lt;br /&gt;
          // We can use our jquery dependency here.&lt;br /&gt;
          return $(&#039;.blue&#039;).show();&lt;br /&gt;
     };&lt;br /&gt;
      &lt;br /&gt;
    /**&lt;br /&gt;
     * @constructor&lt;br /&gt;
     * @alias module:block_overview/helloworld&lt;br /&gt;
     */&lt;br /&gt;
    var greeting = function() {&lt;br /&gt;
        /** @access private */&lt;br /&gt;
        var privateThoughts = &#039;I like the colour blue&#039;;&lt;br /&gt;
        &lt;br /&gt;
        /** @access public */&lt;br /&gt;
        this.publicThoughts = &#039;I like the colour orange&#039;;&lt;br /&gt;
&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * A formal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.formal = function() {&lt;br /&gt;
        return &#039;How do you do?&#039;;&lt;br /&gt;
    };&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * An informal greeting.&lt;br /&gt;
     * @access public&lt;br /&gt;
     * @return {string}&lt;br /&gt;
     */&lt;br /&gt;
    greeting.prototype.informal = function() {&lt;br /&gt;
        return &#039;Wassup!&#039;;&lt;br /&gt;
    };&lt;br /&gt;
    return greeting;&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The most interesting line above is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
define([&#039;jquery&#039;], function($) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All AMD modules must call &amp;quot;define()&amp;quot; as the first and only global scoped piece of code. This ensures the javascript code contains no global variables and will not conflict with any other loaded module. The name of the module does not need to be specified because it is determined from the filename and component (but it can be listed in a comment for JSDoc as shown here). &lt;br /&gt;
&lt;br /&gt;
The first argument to &amp;quot;define&amp;quot; is the list of dependencies for the module. This argument must be passed as an array, even if there is only one. In this example &amp;quot;jquery&amp;quot; is a dependency. &amp;quot;jquery&amp;quot; is shipped as a core module is available to all AMD modules. &lt;br /&gt;
&lt;br /&gt;
The second argument to &amp;quot;define&amp;quot; is the function that defines the module. This function will receive as arguments, each of the requested dependencies in the same order they were requested. In this example we receive JQuery as an argument and we name the variable &amp;quot;$&amp;quot; (it&#039;s a JQuery thing). We can then access JQuery normally through the $ variable which is in scope for any code in our module. &lt;br /&gt;
&lt;br /&gt;
The rest of the code in this example is a standard way to define a Javascript module with public/private variables and methods. There are many ways to do this, this is only one.&lt;br /&gt;
&lt;br /&gt;
It is important that we are returning &#039;greeting&#039;. If there is no return then your module will be declared as undefined.&lt;br /&gt;
&lt;br /&gt;
== Loading modules dynamically ==&lt;br /&gt;
What do you do if you don&#039;t know in advance which modules will be required? Stuffing all possible required modules in the define call is one solution, but it&#039;s ugly and it only works for code that is in an AMD module (what about inline code in the page?). AMD lets you load a dependency any time you like. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
&lt;br /&gt;
// Load a new dependency.&lt;br /&gt;
require([&#039;mod_wiki/timer&#039;], function(timer) {&lt;br /&gt;
   // timer is available to do my bidding.&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Including an external javascript/jquery library ==&lt;br /&gt;
If you want to include a javascript / jquery library downloaded from the internet you can do so as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning: if the library you download, supports AMD but is already &amp;quot;named&amp;quot; you will not be able to include it directly&#039;&#039;&#039;&lt;br /&gt;
e.g. &lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
        define(&amp;quot;typeahead.js&amp;quot;, *[ &amp;quot;jquery&amp;quot; ], function(a0) {&lt;br /&gt;
            return factory(a0);&lt;br /&gt;
        });&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
will not work, as moodle injects it&#039;s own define name when loading the library.&lt;br /&gt;
&lt;br /&gt;
If the library is in AMD format and has a define:&lt;br /&gt;
e.g. i want to include the jquery final countdown timer on my page ( hilios.github.io/jQuery.countdown/ )&lt;br /&gt;
* download the module in both normal and minified versions&lt;br /&gt;
* place the modules in your moodle install e.g. your custom theme dir, or plugin dir&lt;br /&gt;
* /theme/mytheme/amd/src/jquery.countdown.js&lt;br /&gt;
&lt;br /&gt;
you can now include the module and initialise it (there are multiple ways to do this)&lt;br /&gt;
php:&lt;br /&gt;
&lt;br /&gt;
1. Create your own AMD module and initialise it:&lt;br /&gt;
&lt;br /&gt;
In your PHP file:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;page-&amp;gt;requires-&amp;gt;js_call_amd(&#039;theme_mytheme/countdowntimer&#039;, &#039;initialise&#039;, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Javascript module:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/amd/src/countdowntimer.js&lt;br /&gt;
define([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($, c) {&lt;br /&gt;
    return {&lt;br /&gt;
        initialise: function ($params) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#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;
2. Put the javascript into a mustache template:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
// /theme/mytheme/templates/countdowntimer.mustache&lt;br /&gt;
&amp;lt;span id=&amp;quot;clock&amp;quot;&amp;gt;&amp;lt;/span&amp;gt;&lt;br /&gt;
{{#js}}&lt;br /&gt;
require([&#039;jquery&#039;, &#039;theme_mytheme/jquery.countdown&#039;], function($) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
{{/js}}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Call the javascript directly from php (although who would want to put javascript into php? ergh):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_amd_inline(&#039;&lt;br /&gt;
require([&#039;theme_mytheme/jquery.countdown&#039;], function(min) {&lt;br /&gt;
           $(&#039;#clock&#039;).countdown(&#039;2020/10/10&#039;, function(event) {&lt;br /&gt;
             $(this).html(event.strftime(&#039;%D days %H:%M:%S&#039;));&lt;br /&gt;
           });&lt;br /&gt;
});&lt;br /&gt;
&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br&amp;gt;&lt;br /&gt;
Note: It could be useful when you wish to pass a big chunk of data from php directly into a JS variable, to workaround MDL-62468 .&amp;lt;br&amp;gt;&lt;br /&gt;
Example: https://github.com/moodle/moodle/blob/master/media/player/videojs/classes/plugin.php#L386&lt;br /&gt;
&lt;br /&gt;
===More examples of including 3rd-party JS modules===&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=327579#p1317252 Adding custom js via AMD (highcharts) to essential theme]&lt;br /&gt;
&lt;br /&gt;
== Embedding AMD code in a page ==&lt;br /&gt;
So you have created lots of cool Javascript modules. Great. How do we actually call them? Any javascript code that calls an AMD module must execute AFTER the requirejs module loader has finished loading. We have provided a function &amp;quot;js_call_amd&amp;quot; that will call a single function from an AMD module with parameters.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;js_call_amd($modulename, $functionname, $params);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
that will &amp;quot;do the right thing&amp;quot; with your block of AMD code and execute it at the end of the page, after our AMD module loader has loaded. &lt;br /&gt;
Notes:&lt;br /&gt;
* the $modulename is the &#039;componentname/modulename&#039; discussed above&lt;br /&gt;
* the $functionname is the name of a public function exposed by the amd module. &lt;br /&gt;
* the $params is an array of params passed as arguments to the function. These should be simple types that can be handled by json_encode (no recursive arrays, or complex classes please). &lt;br /&gt;
* if the size of the params array is too large (&amp;gt; 1Kb), this will produce a developer warning. Do not attempt to pass large amounts of data through this function, it will pollute the page size. A preferred approach is to pass css selectors for DOM elements that contain data-attributes for any required data, or fetch data via ajax in the background.&lt;br /&gt;
&lt;br /&gt;
AMD / JS code can also be embedded on a page via mustache templates&lt;br /&gt;
see here: https://docs.moodle.org/dev/Templates#What_if_a_template_contains_javascript.3F&lt;br /&gt;
&lt;br /&gt;
== But I have a mega JS file I don&#039;t want loaded on every page? ==&lt;br /&gt;
Loading all JS files at once and stuffing them in the browser cache is the right choice for MOST js files, there are probably some exceptions. For these files, you can rename the javascript file to end with the suffix &amp;quot;-lazy.js&amp;quot; which indicates that the module will not be loaded by default, it will be requested the first time it is used. There is no difference in usage for lazy loaded modules, the require() call looks exactly the same, it&#039;s just that the module name will also have the &amp;quot;-lazy&amp;quot; suffix.&lt;br /&gt;
&lt;br /&gt;
== Useful links ==&lt;br /&gt;
* [https://assets.moodlemoot.org/sites/15/20171004085436/JavaScript-AMD-with-RequireJS-presented-by-Daniel-Roperto-Catalyst.pdf JavaScript AMD with RequireJS] presented by Daniel Roperto, Catalyst. (MoodleMOOT AU 2017)&lt;br /&gt;
* [[Useful_core_Javascript_modules]]&lt;br /&gt;
*[[Guide_to_adding_third_party_jQuery_for_AMD]] by Patrick Thibaudeau&lt;br /&gt;
*[https://moodle.org/mod/forum/discuss.php?d=378112#p1524459 How to get variables from PHP into javascript AMD modules in M3.5] Justin Hunt, on Moodle forums.&lt;br /&gt;
*MDL-67327 JavaScript issues when not following the official documentation, since Moodle 3.8&lt;br /&gt;
&lt;br /&gt;
[[Category:AJAX]]&lt;br /&gt;
[[Category:Javascript]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.7_release_notes&amp;diff=56000</id>
		<title>Moodle 3.7 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.7_release_notes&amp;diff=56000"/>
		<updated>2019-05-02T13:06:06Z</updated>

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

		<summary type="html">&lt;p&gt;Scaroodle: Fixed a typo (to =&amp;gt; two)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039;AJAX (Asynchronous Javascript and XML)&#039;&#039;&#039; is a modern web design technique that allows for more interactivity by making webpages that fetch data in the background and alter themselves without reloading the entire page. This helps to make a page feel much more like an application than a web page. AJAX is a new way of working with existing technologies (including HTML, [[Javascript]], [[CSS]] and the &#039;&#039;XMLHttpRequest object&#039;&#039; amongst others) rather than a new piece of technology in itself.&lt;br /&gt;
&lt;br /&gt;
Although AJAX indicates that XML is used, the term really relates to the group of technologies and in Moodle we tend to favour use of JSON rather than XML as the syntax is lighter and leads to a smaller output. It is also easier to construct from php data structures.&lt;br /&gt;
&lt;br /&gt;
== Ajax in Moodle ==&lt;br /&gt;
{{ Moodle 2.9 }}&lt;br /&gt;
&lt;br /&gt;
The preferred way to write new ajax interactions in Moodle is to use the javascript module &amp;quot;core/ajax&amp;quot; which can directly call existing web service functions. &lt;br /&gt;
&lt;br /&gt;
Some benefits of this system are: &lt;br /&gt;
# No new ajax scripts need auditing for security vulnerabilities&lt;br /&gt;
# Multiple requests can be chained in a single http request&lt;br /&gt;
# Strict type checking for all parameters and return types&lt;br /&gt;
# New webservice functions benefit Ajax interfaces and web service clients&lt;br /&gt;
&lt;br /&gt;
So the steps required to create an ajax interaction are:&lt;br /&gt;
&lt;br /&gt;
# Write or find an existing web service function to handle the ajax interaction: See [[ Web_services ]]&lt;br /&gt;
# White list the web service for ajax. To do this, you can define &#039;ajax&#039; =&amp;gt; true in your function&#039;s definition, in db/services.php. Only functions that are whitelisted using this mechanism will be available to the ajax script.&lt;br /&gt;
# Call the web service from javascript in response to a user action:&lt;br /&gt;
&lt;br /&gt;
Example calling core_get_string:&lt;br /&gt;
&amp;lt;code javascript&amp;gt;&lt;br /&gt;
require([&#039;core/ajax&#039;], function(ajax) {&lt;br /&gt;
    var promises = ajax.call([&lt;br /&gt;
        { methodname: &#039;core_get_string&#039;, args: { component: &#039;mod_wiki&#039;, stringid: &#039;pluginname&#039; } },&lt;br /&gt;
        { methodname: &#039;core_get_string&#039;, args: { component: &#039;mod_wiki&#039;, stringid: &#039;changerate&#039; } }&lt;br /&gt;
    ]);&lt;br /&gt;
&lt;br /&gt;
   promises[0].done(function(response) {&lt;br /&gt;
       console.log(&#039;mod_wiki/pluginname is&#039; + response);&lt;br /&gt;
   }).fail(function(ex) {&lt;br /&gt;
       // do something with the exception&lt;br /&gt;
   });&lt;br /&gt;
&lt;br /&gt;
   promises[1].done(function(response) {&lt;br /&gt;
       console.log(&#039;mod_wiki/changerate is&#039; + response);&lt;br /&gt;
   }).fail(function(ex) {&lt;br /&gt;
       // do something with the exception&lt;br /&gt;
   });&lt;br /&gt;
});&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note: This example chains two separate calls to the &#039;core_get_string&#039; webservice in one http request&lt;br /&gt;
&lt;br /&gt;
Note: Don&#039;t actually fetch strings like this, it is just an example, use the &#039;core/str&#039; module instead.&lt;br /&gt;
&lt;br /&gt;
If there is only a single action, a simpler form is possible (example from Assignment):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
        ajax.call([{&lt;br /&gt;
            methodname: &#039;mod_assign_submit_grading_form&#039;,&lt;br /&gt;
            args: {assignmentid: assignmentid, userid: this._lastUserId, jsonformdata: JSON.stringify(data)},&lt;br /&gt;
            done: this._handleFormSubmissionResponse.bind(this, data, nextUserId),&lt;br /&gt;
            fail: notification.exception&lt;br /&gt;
        }]);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(&#039;notifcation&#039; comes from the &#039;core/notification&#039; javascript module and provides a useful popup error message if the call fails)&lt;br /&gt;
&lt;br /&gt;
To update parts of the UI in response to Ajax changes, consider using [[ Templates ]]&lt;br /&gt;
&lt;br /&gt;
For information on writing AJAX scripts for Moodle before Moodle 2.9 see: [[ AJAX pre 2.9 ]]&lt;br /&gt;
&lt;br /&gt;
Watch a video about using templates with webservices and AJAX in Moodle: https://www.youtube.com/watch?v=UTePjRZqAg8&lt;br /&gt;
&lt;br /&gt;
Tricky things to know about using webservices with ajax calls:&lt;br /&gt;
# Any call to $PAGE-&amp;gt;get_renderer() requires the correct theme be set. If this is done in a webservice - it is likely that the theme needs to be a parameter to the webservice.&lt;br /&gt;
# Text returned from a webservice must be properly filtered. This means it must go through external_format_text or external_format_string (since 3.0 - see MDL-51213) with the correct context.&lt;br /&gt;
# The correct context for 2 is the most specific context relating to the thing being output e.g. for a user&#039;s profile desciption the context is the user context.&lt;br /&gt;
# After adding any dynamic content to a page, Moodle&#039;s filters need to be notified via M.core.event.FILTER_CONTENT_UPDATED (MDL-51222 makes this easier)&lt;br /&gt;
# After adding or changing any webservice definition in db/services.php - you must bump the version number for either the plugin or Moodle and run the upgrade. This will install the webservice in the DB tables so it can be found by ajax.&lt;br /&gt;
&lt;br /&gt;
In some very rare cases - you can mark webservices as safe to call without a session. These should only be used for webservices that return 100% public information and do not consume many resources. A current example is core_get_string. To mark a webservice as safe to call without a session you need to do 2 things. &lt;br /&gt;
# Add &#039;loginrequired&#039; =&amp;gt; false to the service definition in db/services.php&lt;br /&gt;
# Pass &amp;quot;false&amp;quot; as the 3rd argument to the ajax &amp;quot;call&amp;quot; method when calling the webservice. &lt;br /&gt;
The benefit to marking these safe webservice is that (a) they can be called from the login page before we have a session and (b) they will perform faster because they will bypass moodles session code when responding to the webservice call.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[ AJAX pre 2.9 ]]&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Javascript Modules]]&lt;br /&gt;
* [[Javascript FAQ]]&lt;br /&gt;
* [[Javascript]]&lt;br /&gt;
* [[Firebug#Debugging_AJAX_with_Firebug|Debugging AJAX with Firebug]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* [http://www.adaptivepath.com/publications/essays/archives/000385.php &#039;&#039;Ajax: A New Approach to Web Applications&#039;&#039;, the original Ajax article by Adaptive Path] (This link is now dead, but the article is preserved on the  [https://web.archive.org/web/20070225140912/http://www.adaptivepath.com/publications/essays/archives/000385.php Internet Archive])&lt;br /&gt;
* [http://developer.mozilla.org/en/docs/AJAX:Getting_Started &#039;&#039;AJAX: Getting Started&#039;&#039; article on developer.mozilla.org]&lt;br /&gt;
* [http://www.sourcelabs.com/blogs/ajb/2005/12/10_places_you_must_use_ajax.html &#039;&#039;10 places you must use AJAX&#039;&#039; by Adam Bosworth] (Also a dead link...  [https://web.archive.org/web/20060127015713/http://www.sourcelabs.com/blogs/ajb/2005/12/10_places_you_must_use_ajax.html Internet Archive copy])&lt;br /&gt;
* [http://www-128.ibm.com/developerworks/web/library/wa-ajaxtop1/?ca=dgr-lnxw01AjaxHype &#039;&#039;Considering Ajax, Part 1: Cut through the hype&#039;&#039; from IBM developerworks] (Also a dead link... [https://web.archive.org/web/20080602101238/http://www-128.ibm.com/developerworks/web/library/wa-ajaxtop1/?ca=dgr-lnxw01AjaxHype Internet Archive copy])&lt;br /&gt;
* [http://en.wikipedia.org/wiki/Ajax_%28programming%29 Wikipedia article on &#039;&#039;AJAX&#039;&#039;]&lt;br /&gt;
* [http://www.maxkiesler.com/index.php/weblog/comments/how_to_make_your_ajax_applications_accessible/ How to Make Your AJAX Applications Accessible: 40 Tutorials and Articles] (Also a dead link... [https://web.archive.org/web/20090225094656/http://www.maxkiesler.com/index.php/weblog/comments/how_to_make_your_ajax_applications_accessible/ Internet Archive copy])&lt;br /&gt;
*[http://www.ajaxload.info/ AJAX loading icon generator]&lt;br /&gt;
&lt;br /&gt;
[[Category:Javascript]]&lt;br /&gt;
[[Category:AJAX]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Deprecation&amp;diff=54371</id>
		<title>Deprecation</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Deprecation&amp;diff=54371"/>
		<updated>2018-06-08T08:34:26Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: /* What is Moodle&amp;#039;s deprecation policy? */ Add a direct example even here, for the reader who knows nothing about the Moodle scheme versioning&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== What is deprecation? ==&lt;br /&gt;
&lt;br /&gt;
[http://en.wikipedia.org/wiki/Deprecation Deprecation], in its programming sense, is the process of taking older code and marking it as no longer being useful within the codebase, usually because it has been superseded by newer code. The deprecated code is not immediately removed from the codebase because doing so may cause regression errors.&lt;br /&gt;
&lt;br /&gt;
== Why is deprecation needed? ==&lt;br /&gt;
&lt;br /&gt;
In an open source project, the end use of the codebase varies. People may have customisations and plugins that depend on a function that has been targeted for deprecation. Rather than simply removing a function, we must gracefully deprecate the function over a period covered by a number of released versions.&lt;br /&gt;
&lt;br /&gt;
== What is Moodle&#039;s deprecation policy? ==&lt;br /&gt;
&lt;br /&gt;
* Deprecations should only be on master, not on stables (exceptions may be made for some external service integrations)&lt;br /&gt;
* Deprecations apply to all public APIs, classes, and files.&lt;br /&gt;
* Removal of a function, class, or file may only be considered after a minimum of 4 major releases since the deprecation. Example: anything deprecated in 3.2 means that it will be removed in 3.6&lt;br /&gt;
* All deprecations should emit debugging notices where possible&lt;br /&gt;
* All deprecations should be noted in the relevant upgrade.txt&lt;br /&gt;
&lt;br /&gt;
== Moodle Core deprecation process ==&lt;br /&gt;
&lt;br /&gt;
Once it is decided that a function should be deprecated, a two-step process should be followed.&lt;br /&gt;
&lt;br /&gt;
Note that both steps should always happen as earlier as possible in the 6-months period  between major releases, so all developers will have time to adjust their code and ensure it will work in the next release. Obviously, no changes will be allowed after code freeze (the APIs must remain 100% unmodified after it).&lt;br /&gt;
&lt;br /&gt;
Every deprecation should be documented in the corresponding upgrade.txt files &#039;&#039;&#039;at least&#039;&#039;&#039; once, but ideally both on initial deprecation and on final removal.&lt;br /&gt;
&lt;br /&gt;
=== Step 1. Immediate action ===&lt;br /&gt;
&lt;br /&gt;
Deprecation affects only the current master version, in other words, the deprecation only becomes affective after the next [[Releases|major release]].&lt;br /&gt;
&lt;br /&gt;
* If the function is not a member of a class (in other words, it is an independent function), it should be moved, with its PHPDoc and all comments, to &#039;&#039;lib/deprecatedlib.php&#039;&#039;, which is included everywhere. If the function is a class member, it will need to be deprecated in its current location.&lt;br /&gt;
** Deprecated behat step definitions should be moved to lib/tests/behat/behat_deprecated.php, including a call to behat_deprecated::deprecated_message() proposing an alternative to the deprecated method.&lt;br /&gt;
* A debugging message should be added to the function so that, when [[:en:Debugging|developer debugging mode]] is on, attention is drawn to the deprecation. The message should state that the function being called has been deprecated. The message should help a developer whose code currently calls the function that has gone. Tell them what they should do instead.&lt;br /&gt;
&lt;br /&gt;
 debugging(&#039;foobar() is deprecated. Please use foobar::blah() instead.&#039;, DEBUG_DEVELOPER);&lt;br /&gt;
&lt;br /&gt;
* If the deprecated function has been replaced with a new function, ideally the new function should be called from the deprecated function, so that the new functionality is used. This will make maintenance easier moving forward.&lt;br /&gt;
* A &amp;lt;tt&amp;gt;@deprecated&amp;lt;/tt&amp;gt; tag should be added to the PHPDoc for the function description so that IDEs describing the function will note that it is deprecated, documenting which version it was deprecated in and the MDL issue associated with it. See the guidelines in [[Coding_style#.40deprecated_.28and_.40todo.29]].&lt;br /&gt;
* There will need to be an issue associated with the initial part of the deprecation. A second issue needs to be created to finish the job. The first issue will be linked to second issue. The second issue needs to be a sub-task of an appropriate [https://tracker.moodle.org/issues/?jql=%28summary%20~%20%22meta%22%20or%20type%20%3D%20Epic%29%20AND%20summary%20~%20%22together%20deprecated%22%20order%20by%20created&amp;amp;runQuery=true&amp;amp;clear=true deprecation META]. For example, if the current version is 3.1.2, the function will be marked as deprecated in 3.2 and should normally be removed for 3.6, so the second issue should be an issue in a deprecation epic for the 3.6 version (MDL-54740). This second issue should include instructions on how to remove the function so that when it comes time to do so, the task is trivial for any developer.&lt;br /&gt;
* A &amp;lt;tt&amp;gt;@todo&amp;lt;/tt&amp;gt; tag can be added linking to the issues created for further action. (optional)&lt;br /&gt;
* A &amp;lt;tt&amp;gt;@see&amp;lt;/tt&amp;gt; tag can be added to point to the new apis that can be used. (optional)&lt;br /&gt;
* Check the body of the function being deprecated and look for additional function calls which have no other non-deprecated uses and may also be considered for deprecation. If they belong to the same code area they can be deprecated in the same issue.&lt;br /&gt;
&lt;br /&gt;
Longer deprecation periods can be considered for functions that are widely used.&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Final deprecation ===&lt;br /&gt;
&lt;br /&gt;
* If a function has been marked as deprecated for 3.x (eg. 3.1) and set for removal at 3.x+4 (eg. 3.5), soon after the release of 3.x+3.1 (eg. 3.4.1), the 3.x+4 deprecation META will be processed. This means that the deprecated function will undergo final deprecation before 3.x+4, but only in the master version. This allows any potential regressions caused by the final deprecation of the function to be exposed as soon as possible.&lt;br /&gt;
* When a function undergoes final deprecation, all content of the function should be removed. In the skeleton that remains, an error statement should be included that indicates that the function cannot be used anymore. You can also direct developers to the new function(s) in this message.&lt;br /&gt;
&lt;br /&gt;
 throw new coding_exception(&#039;check_potential_filename() can not be used any more, please use new file API&#039;);&lt;br /&gt;
&lt;br /&gt;
* All function parameters should be removed&lt;br /&gt;
* The content of the PHPDoc should be removed, leaving only the &amp;lt;tt&amp;gt;@deprecated&amp;lt;/tt&amp;gt; tag with the notice and, optionally, the replacement information. This includes all &amp;lt;tt&amp;gt;@param&amp;lt;/tt&amp;gt;, &amp;lt;tt&amp;gt;@return&amp;lt;/tt&amp;gt;, and other tags, as well as the description.&lt;br /&gt;
* Please note that previously the final deprecation was 2 versions instead of 4. For example, functions deprecated in 2.9 are throwing exceptions starting from 3.1; however functions deprecated in 3.0 will throw exception in 3.4&lt;br /&gt;
&lt;br /&gt;
== See also... ==&lt;br /&gt;
&lt;br /&gt;
* [[String deprecation]]&lt;br /&gt;
* [[Process]]&lt;br /&gt;
* [[Release process]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Processes]]&lt;br /&gt;
[[Category:Core development]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Privacy_API&amp;diff=54009</id>
		<title>Privacy API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Privacy_API&amp;diff=54009"/>
		<updated>2018-04-09T14:15:39Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Do not use &amp;#039;#&amp;#039;, codechecker will complain about it: Perl-style comments are not allowed; use &amp;quot;// Comment.&amp;quot; instead&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The [https://en.wikipedia.org/wiki/General_Data_Protection_Regulation General Data Protection Regulation] (GDPR) is an EU directive that looks at providing users with more control over their data and how it is processed. This regulation will come into effect on 25th of May 2018 and covers any citizen or permanent resident of the European Union. The directive will be respected by a number of other countries outside of the European Union.&lt;br /&gt;
&lt;br /&gt;
To help institutions become compliant with this new regulation we are adding functionality to Moodle. This includes a number of components, amongst others these include a user’s right to:&lt;br /&gt;
&lt;br /&gt;
* request information on the types of personal data held, the instances of that data, and the deletion policy for each;&lt;br /&gt;
* access all of their data; and&lt;br /&gt;
* be forgotten.&lt;br /&gt;
&lt;br /&gt;
The compliance requirements also extend to installed plugins (including third party plugins). These need to also be able to report what information they store or process regarding users, and have the ability to provide and delete data for a user request.&lt;br /&gt;
&lt;br /&gt;
This document describes the proposed API changes required for plugins which will allow a Moodle installation to become GDPR compliant.&lt;br /&gt;
&lt;br /&gt;
Target Audience: The intended audience for this document is Moodle plugin developers, who are aiming to ensure their plugins are updated to comply with GDPR requirements coming into effect in the EU in May, 2018.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Personal data in Moodle==&lt;br /&gt;
&lt;br /&gt;
From the GDPR Spec, Article 4:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;‘personal data’ means any information relating to an identified or identifiable natural person (‘data subject’); an identifiable natural person is one who can be identified, directly or indirectly, in particular by reference to an identifier such as a name, an identification number, location data, an online identifier or to one or more factors specific to the physical, physiological, genetic, mental, economic, cultural or social identity of that natural person;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In Moodle, we need to consider two main types of personal data; information entered by the user and information stored about the user. The key difference being that information stored about the user will have come from a source other than the user themselves. Both types of data can be used to form a profile of the individual.&lt;br /&gt;
&lt;br /&gt;
The most obvious clue to finding personal data entered by the user is the presence of a userid on a database field. Any data on the record (or linked records) pertaining to that user may be deemed personal data for that user, including things like timestamps and record identification numbers. Additionally, any free text field which allows the user to enter information must also be considered to be the personal data of that user.&lt;br /&gt;
&lt;br /&gt;
Data stored about the user includes things like ratings and comments made on a student submission. These may have been made by an assessor or teacher, but are considered the personal data of the student, as they are considered a reflection of the user’s competency in the subject matter and can be used to form a profile of that individual. &lt;br /&gt;
&lt;br /&gt;
The sections that follow outline what you need to do as a plugin developer to ensure any personal data is advertised and can be accessed and deleted according to the GDPR requirements.&lt;br /&gt;
&lt;br /&gt;
==Background==&lt;br /&gt;
&lt;br /&gt;
===Architecture overview===&lt;br /&gt;
&lt;br /&gt;
A new system for Privacy has been created within Moodle. This is broken down into several main parts and forms the &#039;&#039;core_privacy&#039;&#039; subsystem:&lt;br /&gt;
&lt;br /&gt;
* Some metadata providers - a set of PHP interfaces to be implemented by components for that component to describe the kind of data that it stores, and the purpose for its storage;&lt;br /&gt;
* Some request providers - a set of PHP interfaces to be implemented by components to allow that component to act upon user requests such as the Right to be Forgotten, and a Subject Access Request; and&lt;br /&gt;
* A manager - a concrete class used to bridge components which implement the providers with tools which request their data.&lt;br /&gt;
&lt;br /&gt;
All plugins will implement one metadata provider, and zero, one or two request providers.&lt;br /&gt;
&lt;br /&gt;
The fetching of data is broken into two separate steps:&lt;br /&gt;
&lt;br /&gt;
# Detecting in which Moodle contexts the user has any data; and&lt;br /&gt;
# Exporting all data from each of those contexts.&lt;br /&gt;
&lt;br /&gt;
This has been broken into two steps to later allow administrators to exclude certain contexts from an export - e.g. for courses currently in progress.&lt;br /&gt;
&lt;br /&gt;
A third component will later be added to facilitate the deletion of data within these contexts which will help to satisfy the Right to be Forgotten. This will also use the first step.&lt;br /&gt;
&lt;br /&gt;
===Implementing a provider===&lt;br /&gt;
&lt;br /&gt;
All plugins will need to create a concrete class which implements the relevant metadata and request providers. The exact providers you need to implement will depend on what data you store, and the type of plugin. This is covered in more detail in the following sections of the document.&lt;br /&gt;
&lt;br /&gt;
In order to do so:&lt;br /&gt;
&lt;br /&gt;
# You must create a class called &#039;&#039;provider&#039;&#039; within the namespace &#039;&#039;\your_pluginname\privacy&#039;&#039;.&lt;br /&gt;
# This class must be created at &#039;&#039;path/to/your/plugin/classes/privacy/provider.php&#039;&#039;.&lt;br /&gt;
# You must have your class implement the relevant metadata and request interfaces.&lt;br /&gt;
&lt;br /&gt;
==Plugins which do not store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do not store any personal data. This is usually the case for plugins which just add functionality, or which display the data already stored elsewhere in Moodle.&lt;br /&gt;
&lt;br /&gt;
Some examples of plugin types which might fit this criteria include themes, blocks, filters, editor plugins, etc.&lt;br /&gt;
&lt;br /&gt;
Plugins which cause data to be stored elsewhere in Moodle (e.g. via a subsystem call) are considered to store data.&lt;br /&gt;
&lt;br /&gt;
One examples of a plugin which does not store any data would be the Calendar month block which just displays a view of the user’s calendar. It does not store any data itself.&lt;br /&gt;
&lt;br /&gt;
An example of a plugin which must not use the null provider is the Comments block. The comments block is responsible for data subsequently being stored within Moodle. Although the block doesn’t store anything itself, it interacts with the comments subsystem and is the only component which knows how that data maps to a user.&lt;br /&gt;
&lt;br /&gt;
===Implementation requirements===&lt;br /&gt;
&lt;br /&gt;
In order to let Moodle know that you have audited your plugin, and that you do not store any personal user data, you must implement the &#039;&#039;\core_privacy\local\metadata\null_provider&#039;&#039; interface in your plugin’s provider.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;null_provider&#039;&#039; requires you to define one function &#039;&#039;get_reason()&#039;&#039; which returns the language string identifier within your component.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;block/calendar_month/classes/privacy/provider.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;
&lt;br /&gt;
namespace block_calendar_month\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
    // This plugin does not store any personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\null_provider {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the language string identifier with the component&#039;s language&lt;br /&gt;
     * file to explain why this plugin stores no data.&lt;br /&gt;
     *&lt;br /&gt;
     * @return  string&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_reason() : string {&lt;br /&gt;
        return &#039;privacy:null_reason&#039;;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;block/calendar_month/lang/en/block_calendar_month.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;
$string[&#039;privacy:null_reason&#039;] = &#039;The calendar month block displays information from the Calendar, but does not effect or store any data itself. All changes are made via the Calendar.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That’s it. Congratulations, your plugin now implements the Privacy API.&lt;br /&gt;
&lt;br /&gt;
==Plugins which store personal data==&lt;br /&gt;
&lt;br /&gt;
Many Moodle plugins do store some form of personal data.&lt;br /&gt;
&lt;br /&gt;
In some cases this will be stored within database tables in your plugin, and in other cases this will be in one of Moodle’s core subsystems - for example your plugin may store files, ratings, comments, or tags.&lt;br /&gt;
&lt;br /&gt;
Plugins which do store data will need to:&lt;br /&gt;
&lt;br /&gt;
* Describe the type of data that they store; &lt;br /&gt;
* Provide a way to export that data; and&lt;br /&gt;
* Provide a way to delete that data.&lt;br /&gt;
&lt;br /&gt;
Data is described via a &#039;&#039;metadata&#039;&#039; provider, and it is both exported and deleted via an implementation of a &#039;&#039;request&#039;&#039; provider.&lt;br /&gt;
&lt;br /&gt;
These are both explained in the sections below.&lt;br /&gt;
&lt;br /&gt;
===Describing the type of data you store===&lt;br /&gt;
&lt;br /&gt;
In order to describe the type of data that you store, you must implement the &#039;&#039;\core_privacy\local\metadata\provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
This interfaces requires that you define one function: &#039;&#039;get_metadata&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
There are several types of item to describe the data that you store. These are for:&lt;br /&gt;
&lt;br /&gt;
* Items in the Moodle database;&lt;br /&gt;
* Items stored by you in a Moodle subsystem - for example files, and ratings; and&lt;br /&gt;
* User preferences stored site-wide within Moodle for your plugin&lt;br /&gt;
&lt;br /&gt;
Note: All fields should include a description from a language string within your plugin.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.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;
&lt;br /&gt;
namespace mod_forum\privacy;&lt;br /&gt;
use \core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
class provider implements &lt;br /&gt;
    // This plugin does store personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider {&lt;br /&gt;
    public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
        return $collection;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store content in a Moodle subsystem====&lt;br /&gt;
&lt;br /&gt;
Many plugins will use one of the core Moodle subsystems to store data.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer we do not expect you to describe those subsystems in detail, but we do need to know that you use them and to know what you use them for.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;link_subsystem()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;link_subsystem(&lt;br /&gt;
        &#039;core_files&#039;,&lt;br /&gt;
        &#039;privacy:metadata:core_files&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.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;
$string[&#039;privacy:metadata:core_files&#039;] = &#039;The forum stores files which have been uploaded by the user to form part of a forum post.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Describing data stored in database tables====&lt;br /&gt;
&lt;br /&gt;
Most Moodle plugins will store some form of user data in their own database tables.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each database table, and each field which includes user data.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_database_table(&lt;br /&gt;
        &#039;forum_discussion_subs&#039;,&lt;br /&gt;
         [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:userid&#039;,&lt;br /&gt;
            &#039;discussionid&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:discussionid&#039;,&lt;br /&gt;
            &#039;preference&#039; =&amp;gt; &#039;privacy:metadata:forum_discussion_subs:preference&#039;,&lt;br /&gt;
&lt;br /&gt;
         ],&lt;br /&gt;
        &#039;privacy:metadata:forum_discussion_subs&#039;&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/lang/en/forum.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;
$string[&#039;privacy:metadata:forum_discussion_subs&#039;] = &#039;Information about the subscriptions to individual forum discussions. This includes when a user has chosen to subscribe to a discussion, or to unsubscribe from one where they would otherwise be subscribed.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:userid&#039;] = &#039;The ID of the user with this subscription preference.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:discussionid&#039;] = &#039;The ID of the discussion that was subscribed to.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:forum_discussion_subs:preference&#039;] = &#039;The start time of the subscription.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you store site-wide user preferences====&lt;br /&gt;
&lt;br /&gt;
Many plugins will include one or more user preferences. Unfortunately this is one of Moodle’s older components and many of the values stored are not pure user preferences. Each plugin should be aware of how it handles its own preferences and is best placed to determine whether they are site-wide preferences, or per-instance preferences.&lt;br /&gt;
&lt;br /&gt;
Whilst most of these will have a fixed name (e.g. &#039;&#039;filepicker_recentrepository&#039;&#039;), some will include a variable of some kind (e.g. &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039;). Only the general name needs to be indicated rather than one copy for each preference.&lt;br /&gt;
&lt;br /&gt;
Also, these should only be &#039;&#039;site-wide&#039;&#039; user preferences which do not belong to a specific Moodle context.&lt;br /&gt;
&lt;br /&gt;
In the above examples:&lt;br /&gt;
&lt;br /&gt;
* Preference &#039;&#039;filepicker_recentrepository&#039;&#039; belongs to the file subsystem, and is a site-wide preference affecting the user anywhere that they view the filepicker.&lt;br /&gt;
* Preference &#039;&#039;tool_usertours_tour_completion_time_2&#039;&#039; belongs to user tours. User tours are a site-wide feature which can affect many parts of Moodle and cross multiple contexts.&lt;br /&gt;
&lt;br /&gt;
In some cases a value may be stored in the preferences table but is known to belong to a specific context within Moodle. In these cases they should be stored as metadata against that context rather than as a site-wide user preference.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;add_user_preference()&#039;&#039; method on the &#039;&#039;collection&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Any plugin providing user preferences must also implement the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;add_user_preference(&#039;tool_usertours_tour_completion_time,&lt;br /&gt;
        &#039;privacy:metadata:preference:tool_usertours_tour_completion_time&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;admin/tool/usertours/lang/en/tool_usertours.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;
$string[&#039;privacy:metadata:tool_usertours_tour_completion_time&#039;] = &#039;The time that a specific user tour was last completed by a user.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Indicating that you export data to an external location====&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with external systems - for example cloud-based services. Often this external location is configurable within the plugin either at the site or the instance level.&lt;br /&gt;
&lt;br /&gt;
As a plugin developer you will need to describe each &#039;&#039;type&#039;&#039; of target destination, alongside a list of each exported field which includes user data.&lt;br /&gt;
The &#039;&#039;actual&#039;&#039; destination does not need to be described as this can change based on configuration.&lt;br /&gt;
&lt;br /&gt;
You can indicate this by calling the &#039;&#039;link_external_location()&#039;&#039; method on the collection.&lt;br /&gt;
&lt;br /&gt;
=====Example=====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/lti/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function get_metadata(collection $collection) : collection {&lt;br /&gt;
&lt;br /&gt;
    $collection-&amp;gt;link_external_location(&#039;lti_client&#039;, [&lt;br /&gt;
            &#039;userid&#039; =&amp;gt; &#039;privacy:metadata:lti_client:userid&#039;,&lt;br /&gt;
            &#039;fullname&#039; =&amp;gt; &#039;privacy:metadata:lti_client:fullname&#039;,&lt;br /&gt;
        ], &#039;privacy:metadata:lti_client&#039;);&lt;br /&gt;
&lt;br /&gt;
    return $collection;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/lti/lang/en/lti.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;
$string[&#039;privacy:metadata:lti_client&#039;] = &#039;In order to integrate with a remote LTI service, user data needs to be exchanged with that service.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:userid&#039;] = &#039;The userid is sent from Moodle to allow you to access your data on the remote system.&#039;;&lt;br /&gt;
$string[&#039;privacy:metadata:lti_client:fullname&#039;] = &#039;Your full name is sent to the remote system to allow a better user experience.&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to export user data===&lt;br /&gt;
&lt;br /&gt;
In order to export the user data that you store, you must implement the relevant request provider.&lt;br /&gt;
&lt;br /&gt;
We have named these request providers because they are called in response to a specific request from a user to access their information.&lt;br /&gt;
&lt;br /&gt;
There are several different types of request provider, and you may need to implement several of these, depending on the type and nature of your plugin.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking plugins will fit into one of the following categories:&lt;br /&gt;
&lt;br /&gt;
* Plugins which are a subplugin of another plugin. Examples include &#039;&#039;assignsubmission&#039;&#039;, &#039;&#039;atto&#039;&#039;, and &#039;&#039;datafield&#039;&#039;;&lt;br /&gt;
* Plugins which are typically called by a Moodle subsystem. Examples include &#039;&#039;qtype&#039;&#039;, and &#039;&#039;profilefield&#039;&#039;;&lt;br /&gt;
* All other plugins which store data.&lt;br /&gt;
&lt;br /&gt;
Most plugins will fit into this final category, whilst other plugins may fall into several categories.&lt;br /&gt;
Plugins which &#039;&#039;define&#039;&#039; a subplugin will also be responsible for  collecting this data from their subplugins.&lt;br /&gt;
&lt;br /&gt;
A final category exists - plugins which store user preferences. In some cases this may be the &#039;&#039;only&#039;&#039; provider implemented.&lt;br /&gt;
&lt;br /&gt;
====Standard plugins which store data====&lt;br /&gt;
&lt;br /&gt;
A majority of Moodle plugins will fit into this category and will be required to implement the &#039;&#039;\core_privacy\local\request\plugin\provider&#039;&#039; interface. This interface requires that you define two functions:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;get_contexts_for_userid&#039;&#039; - to explain where data is held within Moodle for your plugin; and&lt;br /&gt;
* &#039;&#039;export_user_data&#039;&#039; - to export a user’s personal data from your plugin.&lt;br /&gt;
&lt;br /&gt;
These APIs make use of the Moodle &#039;&#039;context&#039;&#039; system to hierarchically store this data.&lt;br /&gt;
&lt;br /&gt;
====Retrieving the list of contexts====&lt;br /&gt;
&lt;br /&gt;
Contexts are retrieved using the &#039;&#039;get_contexts_for_userid&#039;&#039; function which takes the ID of the user being fetched, and returns a list of contexts in which the user has any data.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The function returns a &#039;&#039;\core_privacy\local\request\contextlist&#039;&#039; which is used to keep a set of contexts together in a fixed fashion.&lt;br /&gt;
&lt;br /&gt;
Because a Subject Access Request covers &#039;&#039;every&#039;&#039; piece of data that is held for a user within Moodle, efficiency and performance is highly important. As a result, contexts are added to the &#039;&#039;contextlist&#039;&#039; by defining one or more SQL queries which return just the contextid. Multiple SQL queries can be added as required.&lt;br /&gt;
&lt;br /&gt;
Many plugins will interact with specific subsystems and store data within them.&lt;br /&gt;
These subsystems will also provide a way in which to link the data that you have stored with your own database tables.&lt;br /&gt;
At present these are still a work in progress and only the &#039;&#039;core_ratings&#039;&#039; subsystem includes this.&lt;br /&gt;
&lt;br /&gt;
=====Basic example=====&lt;br /&gt;
&lt;br /&gt;
The following example simply fetches the contextid for all forums where a user has a single discussion (note: this is an incomplete example):&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
        $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
&lt;br /&gt;
        $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                 FROM {context} c&lt;br /&gt;
           INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
           INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
           INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
                WHERE (&lt;br /&gt;
                d.userid        = :discussionuserid&lt;br /&gt;
                )&lt;br /&gt;
        &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
        $params = [&lt;br /&gt;
            &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
            &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
            &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        ];&lt;br /&gt;
&lt;br /&gt;
        $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=====More complete example=====&lt;br /&gt;
&lt;br /&gt;
The following example includes a link to core_rating. &lt;br /&gt;
It will find any forum, forum discussion, or forum post where the user has any data, including:&lt;br /&gt;
&lt;br /&gt;
* Per-forum digest preferences;&lt;br /&gt;
* Per-forum subscription preferences;&lt;br /&gt;
* Per-forum read tracking preferences;&lt;br /&gt;
* Per-discussion subscription preferences;&lt;br /&gt;
* Per-post read data (if a user has read a post or not); and&lt;br /&gt;
* Per-post rating data.&lt;br /&gt;
&lt;br /&gt;
In the case of the rating data, this will include any post where the user has rated the post of another user.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Get the list of contexts that contain user information for the specified user.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int           $userid       The user to search.&lt;br /&gt;
 * @return  contextlist   $contextlist  The list of contexts used in this plugin.&lt;br /&gt;
 */&lt;br /&gt;
public static function get_contexts_for_userid(int $userid) : contextlist {&lt;br /&gt;
    $ratingsql = \core_rating\privacy\provider::get_sql_join(&#039;rat&#039;, &#039;mod_forum&#039;, &#039;post&#039;, &#039;p.id&#039;, $userid);&lt;br /&gt;
    // Fetch all forum discussions, and forum posts.&lt;br /&gt;
    $sql = &amp;quot;SELECT c.id&lt;br /&gt;
                FROM {context} c&lt;br /&gt;
        INNER JOIN {course_modules} cm ON cm.id = c.instanceid AND c.contextlevel = :contextlevel&lt;br /&gt;
        INNER JOIN {modules} m ON m.id = cm.module AND m.name = :modname&lt;br /&gt;
        INNER JOIN {forum} f ON f.id = cm.instance&lt;br /&gt;
            LEFT JOIN {forum_discussions} d ON d.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_posts} p ON p.discussion = d.id&lt;br /&gt;
            LEFT JOIN {forum_digests} dig ON dig.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_subscriptions} sub ON sub.forum = f.id&lt;br /&gt;
            LEFT JOIN {forum_track_prefs} pref ON pref.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_read} hasread ON hasread.forumid = f.id&lt;br /&gt;
            LEFT JOIN {forum_discussion_subs} dsub ON dsub.forum = f.id&lt;br /&gt;
            {$ratingsql-&amp;gt;join}&lt;br /&gt;
                WHERE (&lt;br /&gt;
                p.userid        = :postuserid OR&lt;br /&gt;
                d.userid        = :discussionuserid OR&lt;br /&gt;
                dig.userid      = :digestuserid OR&lt;br /&gt;
                sub.userid      = :subuserid OR&lt;br /&gt;
                pref.userid     = :prefuserid OR&lt;br /&gt;
                hasread.userid  = :hasreaduserid OR&lt;br /&gt;
                dsub.userid     = :dsubuserid OR&lt;br /&gt;
                {$ratingsql-&amp;gt;userwhere}&lt;br /&gt;
            )&lt;br /&gt;
    &amp;quot;;&lt;br /&gt;
&lt;br /&gt;
    $params = [&lt;br /&gt;
        &#039;modname&#039;           =&amp;gt; &#039;forum&#039;,&lt;br /&gt;
        &#039;contextlevel&#039;      =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;postuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;discussionuserid&#039;  =&amp;gt; $userid,&lt;br /&gt;
        &#039;digestuserid&#039;      =&amp;gt; $userid,&lt;br /&gt;
        &#039;subuserid&#039;         =&amp;gt; $userid,&lt;br /&gt;
        &#039;prefuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
        &#039;hasreaduserid&#039;     =&amp;gt; $userid,&lt;br /&gt;
        &#039;dsubuserid&#039;        =&amp;gt; $userid,&lt;br /&gt;
    ];&lt;br /&gt;
    $params += $ratingsql-&amp;gt;params;&lt;br /&gt;
&lt;br /&gt;
    $contextlist = new \core_privacy\local\request\contextlist();&lt;br /&gt;
    $contextlist-&amp;gt;add_from_sql($sql, $params);&lt;br /&gt;
&lt;br /&gt;
    return $contextlist;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Exporting user data====&lt;br /&gt;
&lt;br /&gt;
After determining where in Moodle your plugin holds data about a user, the &#039;&#039;\core_privacy\manager&#039;&#039; will then ask your plugin to export all user data for a subset of those locations.&lt;br /&gt;
&lt;br /&gt;
This is achieved through use of the &#039;&#039;export_user_data&#039;&#039; function which takes the list of approved contexts in a &#039;&#039;\core_privacy\local\request\approved_contextlist&#039;&#039; object.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user data for the specified user, in the specified contexts, using the supplied exporter instance.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   approved_contextlist    $contextlist    The approved contexts to export information for.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_data(approved_contextlist $contextlist) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;approved_contextlist&#039;&#039; includes both the user record, and a list of contexts, which can be retrieved by either processing it as an Iterator, or by calling &#039;&#039;get_contextids()&#039;&#039; or &#039;&#039;get_contexts()&#039;&#039; as required.&lt;br /&gt;
&lt;br /&gt;
Data is exported using a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which is described in further detail below.&lt;br /&gt;
&lt;br /&gt;
===Plugins which store user preferences===&lt;br /&gt;
&lt;br /&gt;
Many plugins store a variety of user preferences, and must therefore export them.&lt;br /&gt;
&lt;br /&gt;
Since user preferences are a site-wide preference, these are exported separately to other user data.&lt;br /&gt;
In some cases the only data present is user preference data, whilst in others there is a combination of user-provided data, and user preferences.&lt;br /&gt;
&lt;br /&gt;
Storing of user preferences is achieved through implementation of the &#039;&#039;\core_privacy\local\request\preference_provider&#039;&#039; interface which defines one required function -- &#039;&#039;export_user_preferences&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Export all user preferences for the plugin.&lt;br /&gt;
 *&lt;br /&gt;
 * @param   int         $userid The userid of the user whose data is to be exported.&lt;br /&gt;
 */&lt;br /&gt;
public static function export_user_preferences(int $userid) {&lt;br /&gt;
    $markasreadonnotification = get_user_preference(&#039;markasreadonnotification&#039;, null, $userid);&lt;br /&gt;
    if (null !== $markasreadonnotification) {&lt;br /&gt;
        switch ($markasreadonnotification) {&lt;br /&gt;
            case 0:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationno&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
            case 1:&lt;br /&gt;
            default:&lt;br /&gt;
                $markasreadonnotificationdescription = get_string(&#039;markasreadonnotificationyes&#039;, &#039;mod_forum&#039;);&lt;br /&gt;
                break;&lt;br /&gt;
        }&lt;br /&gt;
        writer::export_user_preference(&#039;mod_forum&#039;, &#039;markasreadonnotification&#039;, $markasreadonnotification, $markasreadonnotificationdescription);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which define a subplugin===&lt;br /&gt;
&lt;br /&gt;
Many plugin types are also able to define their own subplugins and will need to define a contract between themselves and their subplugins in order to fetch their data.&lt;br /&gt;
&lt;br /&gt;
This is required as the parent plugin and the child subplugin should be separate entities and the parent plugin must be able to function if one or more of its subplugins are uninstalled.&lt;br /&gt;
&lt;br /&gt;
The parent plugin is responsible for defining the contract,  and for interacting with its subplugins, though we intend to create helpers to make this easier.&lt;br /&gt;
&lt;br /&gt;
The parent plugin should define a new interface for each type of subplugin that it defines. This interface should extend the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface.&lt;br /&gt;
&lt;br /&gt;
====Example====&lt;br /&gt;
&lt;br /&gt;
The following example defines the contract that assign submission subplugins may be required to implement.&lt;br /&gt;
&lt;br /&gt;
The assignment module is responsible for returning the contexts of all assignments where a user has data, but in some cases it is unaware of all of those cases - for example if a Teacher comments on a student submission it may not be aware of these as the information about this interaction may not be stored within its own tables.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/assign/privacy/assignsubmission_provider.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;
&lt;br /&gt;
namespace mod_assign\privacy;&lt;br /&gt;
use \core_privacy\local\metadata\collection;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
interface assignsubmission_provider extends&lt;br /&gt;
    // This Interface defines a subplugin.&lt;br /&gt;
    \core_privacy\local\request\subplugin_provider {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Get the SQL required to find all submission items where this user has had any involvements. &lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @return  \stdClass                   Object containing the join, params, and where used to select a these records from the database.&lt;br /&gt;
     */&lt;br /&gt;
    public static function get_items_with_user_interaction(int $userid) : \stdClass ;&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Export all relevant user submissions information which match the combination of userid and attemptid.&lt;br /&gt;
     *&lt;br /&gt;
     * @param   int           $userid       The user to search.&lt;br /&gt;
     * @param   \context      $context      The context to export this submission against.&lt;br /&gt;
     * @param   array         $subcontext   The subcontext within the context to export this information&lt;br /&gt;
     * @param   int           $attid        The id of the submission to export.&lt;br /&gt;
     */&lt;br /&gt;
    public static function export_user_submissions(int $userid, \context $context, array $subcontext, int $attid) ;&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are subplugins to another plugin===&lt;br /&gt;
&lt;br /&gt;
If you are developing a sub-plugin of another plugin, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subplugin type should define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subplugin_provider&#039;&#039; interface and it is up to the parent plugin to define how they will interact with their children.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/pluginname/classes/privacy/provider.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;
namespace assignsubmission\onlinetext;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    // This plugin does store personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    // This plugin is a subplugin of assign and must meet that contract.&lt;br /&gt;
    \mod_assign\privacy\assignsubmission_provider {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Plugins which are typically called by a Moodle subsystem===&lt;br /&gt;
&lt;br /&gt;
There are a number of plugintypes in Moodle which are typically called by a specific Moodle subsystem.&lt;br /&gt;
&lt;br /&gt;
Some of these are &#039;&#039;only&#039;&#039; called by that subsystem, for example plugins which are of the &#039;&#039;plagiarism&#039;&#039; plugintype should never be called directly, but are always invoked via the &#039;&#039;core_plagiarism&#039;&#039; subsystem.&lt;br /&gt;
&lt;br /&gt;
Conversely, there maybe other plugintypes which can be called both via a subsystem, and in some other fashion. We are still determining whether any plugintypes currently fit this pattern.&lt;br /&gt;
&lt;br /&gt;
If you are developing a plugin which belongs to a specific subsystem, then you will have to look at the relevant plugin in order to determine the exact contract.&lt;br /&gt;
&lt;br /&gt;
Each subsystem will define a new interface which extends the &#039;&#039;\core_privacy\local\request\plugin\subsystem_provider&#039;&#039; interface and it is up to that subsystem to define how they will interact with those plugins.&lt;br /&gt;
&lt;br /&gt;
The principles remain the same, but the exact implementation will differ depending upon requirements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;plagiarism/detectorator/classes/privacy/provider.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;
namespace plagiarism_detectorator\privacy;&lt;br /&gt;
&lt;br /&gt;
class provider implements&lt;br /&gt;
    // This plugin does export personal user data.&lt;br /&gt;
    \core_privacy\local\metadata\provider,&lt;br /&gt;
&lt;br /&gt;
    // This plugin is always linked against another activity module via the Plagiarism API.&lt;br /&gt;
    \core_plagiarism\privacy\plugin_provider {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Exporting data===&lt;br /&gt;
&lt;br /&gt;
Any plugin which stores data must also export it.&lt;br /&gt;
&lt;br /&gt;
To cater for this the privacy API includes a &#039;&#039;\core_privacy\local\request\content_writer&#039;&#039;, which defines a set of functions to store different types of data.&lt;br /&gt;
&lt;br /&gt;
Broadly speaking data is broken into the following types:&lt;br /&gt;
&lt;br /&gt;
* Data - this is the object being described. For example the post content in a forum post;&lt;br /&gt;
* Related data - this is data related to the object being stored. For example, ratings of a forum post;&lt;br /&gt;
* Metadata - This is metadata about the main object. For example whether you are subscribed to a forum discussion;&lt;br /&gt;
* User preferences - this is data about a site-wide preference;&lt;br /&gt;
* Files - Any files that you are stored within Moodle on behalf of this plugin; and&lt;br /&gt;
* Custom files - For custom file formats - e.g. a calendar feed for calendar data. These should be used sparingly.&lt;br /&gt;
&lt;br /&gt;
Each piece of data is stored against a specific Moodle &#039;&#039;context&#039;&#039;, which will define how the data is structured within the exporter.&lt;br /&gt;
Data, and Related data only accept the &#039;&#039;stdClass&#039;&#039; object, whilst metadata should be stored as a set of key/value pairs which include a description.&lt;br /&gt;
&lt;br /&gt;
In some cases the data being stored belongs within an implicit structure. For example, one forum has many forum discussions, which each have a number of forum posts. This structure is represented by an &#039;&#039;array&#039;&#039; referred to as a &#039;&#039;subcontext&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;content_writer&#039;&#039; must &#039;&#039;always&#039;&#039; be called with a specific context, and can be called as follows:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.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;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
writer::with_context($context)&lt;br /&gt;
    -&amp;gt;export_data($subcontext, $post)&lt;br /&gt;
    -&amp;gt;export_area_files($subcontext, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id)&lt;br /&gt;
    -&amp;gt;export_metadata($subcontext, &#039;postread&#039;, (object) [&#039;firstread&#039; =&amp;gt; $firstread], new \lang_string(&#039;privacy:export:post:postread&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Any text field which supports Moodle files must also be rewritten:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/forum/classes/privacy/provider.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;
use \core_privacy\local\request\writer;&lt;br /&gt;
&lt;br /&gt;
writer::with_context($context)&lt;br /&gt;
    -&amp;gt;rewrite_pluginfile_urls($postarea, &#039;mod_forum&#039;, &#039;post&#039;, $post-&amp;gt;id, $post-&amp;gt;message);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Providing a way to delete user data===&lt;br /&gt;
&lt;br /&gt;
Deleting user data is also implemented in the request interface. There are two methods that need to be created. The first one to remove all user data from a context, the other to remove user data for a specific user in a list of contexts.&lt;br /&gt;
&lt;br /&gt;
====Delete for a context====&lt;br /&gt;
&lt;br /&gt;
A context is given and all user data (for all users) is to be deleted from the plugin. This will be called when the retention period for the plugin has expired to adhere to the privacy by design requirement.�&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_data_for_all_users_in_context(deletion_criteria $criteria) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    $context = $criteria-&amp;gt;get_context();&lt;br /&gt;
    if (empty($context)) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
    $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid]);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Delete personal information for a specific user and context(s)====&lt;br /&gt;
&lt;br /&gt;
An &#039;&#039;approved_contextlist&#039;&#039; is given and user data related to that user should either be completely deleted, or overwritten if a structure needs to be maintained. This will be called when a user has requested the right to be forgotten. All attempts should be made to delete this data where practical while still allowing the plugin to be used by other users.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;mod/choice/classes/privacy/provider.php&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public static function delete_data_for_user(approved_contextlist $contextlist) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
    &lt;br /&gt;
    if (empty($contextlist-&amp;gt;count())) {&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
    $userid = $contextlist-&amp;gt;get_user()-&amp;gt;id;&lt;br /&gt;
    foreach ($contextlist-&amp;gt;get_contexts() as $context) {&lt;br /&gt;
        $instanceid = $DB-&amp;gt;get_field(&#039;course_modules&#039;, &#039;instance&#039;, [&#039;id&#039; =&amp;gt; $context-&amp;gt;instanceid], MUST_EXIST);&lt;br /&gt;
        $DB-&amp;gt;delete_records(&#039;choice_answers&#039;, [&#039;choiceid&#039; =&amp;gt; $instanceid, &#039;userid&#039; =&amp;gt; $userid]);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Subject Access Request FAQ]]&lt;br /&gt;
* [[:en:GDPR|GDPR]] in the user documentation&lt;br /&gt;
&lt;br /&gt;
[[Category:GDPR]]&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.4_release_notes&amp;diff=53781</id>
		<title>Moodle 3.4 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.4_release_notes&amp;diff=53781"/>
		<updated>2018-03-07T23:28:58Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: /* Server requirements */ OSes not properly updated could prevent the connection to SSL/TLS secured resources due to old/missing root CA certificates (https://moodle.org/mod/forum/discuss.php?d=366514#p1478917)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 13 November 2017&lt;br /&gt;
 &lt;br /&gt;
Here is [https://tracker.moodle.org/issues/?jql=project%20%3D%20mdl%20AND%20resolution%20%3D%20fixed%20AND%20fixVersion%20in%20(3.4)%20ORDER%20BY%20priority%20DESC the full list of fixed issues in 3.4].&lt;br /&gt;
&lt;br /&gt;
See our [https://docs.moodle.org/34/en/New_features New Features page] for a more user-friendly introduction to Moodle 3.4 with screenshots.&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from previous version, make sure you read the [https://docs.moodle.org/34/en/Upgrading Upgrading] documentation. &lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.0 or later (if upgrading from earlier versions, you must upgrade to 3.0.10 as a first step)&lt;br /&gt;
* PHP version: minimum PHP 7.0.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.3&#039;&#039;. PHP 7.1.x and 7.2.x are supported too. PHP 7.x could have some [https://docs.moodle.org/dev/Moodle_and_PHP7#Can_I_use_PHP7_yet.3F engine limitations]. &lt;br /&gt;
* PHP extension &#039;&#039;&#039;intl&#039;&#039;&#039; is now required in Moodle 3.4 (it was recommended in 2.0 onwards) &lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.3&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2008&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 10.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://whatbrowser.org&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle 3.4:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
===Calendar improvements===&lt;br /&gt;
&lt;br /&gt;
* MDL-59333 - Calendar Improvements&lt;br /&gt;
* MDL-1322 - Calendar entries in monthly view should include course shortname&lt;br /&gt;
* MDL-59382 - Create calendar event quick-add&lt;br /&gt;
* MDL-59390 - Add navigation of all calendar views without page reload&lt;br /&gt;
* MDL-59394 - Add support for drag and drop of calendar events&lt;br /&gt;
* MDL-59386 - Add support for creation and update of calendar events using a modal dialogue&lt;br /&gt;
* MDL-59890 - Add support for calendar events at the category level&lt;br /&gt;
&lt;br /&gt;
===Management of course participants===&lt;br /&gt;
&lt;br /&gt;
* MDL-59290 - Merge Course Participants and Enrolled Users pages&lt;br /&gt;
* MDL-59564 - Add bulk editing of enrolment status/dates for users in the course participants page&lt;br /&gt;
* MDL-59364 - Remove the &amp;quot;Brief / User Details&amp;quot; functionality from the participants page&lt;br /&gt;
* MDL-59365 - Enrol Users button on participants page&lt;br /&gt;
* MDL-59366 - Add filter controls to the participants page to allow custom filtering&lt;br /&gt;
* MDL-59367 - Add a roles column to participants page&lt;br /&gt;
* MDL-59368 - Add a groups column to the participants page&lt;br /&gt;
* MDL-59369 - Add a status column to the participants page&lt;br /&gt;
* MDL-59436 - Remove the columns from the participants page that are not in showuseridentity&lt;br /&gt;
* MDL-59821 - Add &amp;quot;Proceed to course content&amp;quot; to participants page&lt;br /&gt;
&lt;br /&gt;
===Other highlights===&lt;br /&gt;
&lt;br /&gt;
* MDL-57791 - Implement analytics engine in Moodle&lt;br /&gt;
* MDL-59313 - Add links and a drop down to navigate between activities&lt;br /&gt;
* MDL-37361 - Allow teachers to mark activities as completed&lt;br /&gt;
&lt;br /&gt;
===Backup, restore and import===&lt;br /&gt;
&lt;br /&gt;
* MDL-35429 - Correct the permissions required to download and restore course automated backups&lt;br /&gt;
* MDL-9367 - Restore with roll forward changes dates for user data&lt;br /&gt;
* MDL-59518 - Restore date should not roll for user created data - Core components&lt;br /&gt;
&lt;br /&gt;
===Global search===&lt;br /&gt;
&lt;br /&gt;
* MDL-55356 - Index contents of the restored courses&lt;br /&gt;
* MDL-59523 - Course reset doesn&#039;t always shift dates&lt;br /&gt;
* MDL-58957 - Global search: Make it possible to search blocks&lt;br /&gt;
* MDL-59039 - Global search: Allow partial indexing (in scheduled task)&lt;br /&gt;
&lt;br /&gt;
===Authentication===&lt;br /&gt;
&lt;br /&gt;
* MDL-30634 - Assign arbitrary system roles via LDAP sync&lt;br /&gt;
* MDL-58544 - Add option to trust email of an OAuth provider&lt;br /&gt;
* MDL-59844 - Enable OAuth 2 token-based authentication for requests in webdav_client&lt;br /&gt;
* MDL-59459 - Global Search: Increase file indexing coverage&lt;br /&gt;
* MDL-59913 - Global search: Allow search of non-enrolled courses&lt;br /&gt;
&lt;br /&gt;
===Functional changes===&lt;br /&gt;
&lt;br /&gt;
* MDL-55358 - LIS Group Variables support in LTI&lt;br /&gt;
* MDL-36501 - Should have checkbox for extra credit when you add a grade item&lt;br /&gt;
* MDL-28574 - Web services: Manage tokens page should show tokens for all users&lt;br /&gt;
* MDL-26976 - Display space used in My Private Files&lt;br /&gt;
* MDL-35668 - Performance improvement in Server files repository&lt;br /&gt;
* MDL-49398 - Performance improvement due to Role definition caching &amp;amp; accesslib refactoring&lt;br /&gt;
* MDL-60002 - Assignment grading: Adding back &amp;quot;Save and show next&amp;quot;&lt;br /&gt;
* MDL-58889 - Make section titles and course titles more accessible in Boost&lt;br /&gt;
* MDL-57455 - Allow to tag database entries&lt;br /&gt;
* MDL-36985 - Assignment: automatically remove embedded files that are no longer linked from submission text. Reduce the size of &amp;quot;Download all submissions&amp;quot;&lt;br /&gt;
* MDL-59702 - Lesson overview report does not respect value of showuseridentity setting&lt;br /&gt;
* MDL-59460 - Forum: make Subscription mode setting configurable&lt;br /&gt;
&lt;br /&gt;
===For administrators===&lt;br /&gt;
&lt;br /&gt;
Please read carefully: [https://docs.moodle.org/34/en/Upgrading#Possible_issues_that_may_affect_you_in_Moodle_3.4 Possible issues that may affect you in Moodle 3.4]&lt;br /&gt;
&lt;br /&gt;
* MDL-42834 - Deprecate loginhttps. Sites that used to use this setting will now be served via https always&lt;br /&gt;
* MDL-46269 - Tool to [https://docs.moodle.org/34/en/HTTPS_conversion_tool convert http embedded content to https] where available&lt;br /&gt;
* MDL-58388 - Let the admin control if the course end date form field in course settings is enabled by default&lt;br /&gt;
* MDL-60211 - New filters for User Tours&lt;br /&gt;
* MDL-59123 - Compile SCSS files on the command-line&lt;br /&gt;
* MDL-58567 - Upgrade: Show upgrade times&lt;br /&gt;
* MDL-55652 - Missing index on (timemodified) in grade_items_history table and several other grade history tables. This will increase performance of various reports but may also slow down Moodle upgrade&lt;br /&gt;
* MDL-60094 - Add CLI script to kill all sessions&lt;br /&gt;
* MDL-59495 - Register and publish courses with moodle.net only, remove support for alternative hubs&lt;br /&gt;
* MDL-59206 - Trigger an event in add_to_config_log function&lt;br /&gt;
* MDL-57115 - Move &amp;quot;Messages&amp;quot; block out from the standard Moodle distribution&lt;br /&gt;
* MDL-57734 - SEO - Create admin setting to be able to enable or disable search engine indexing for sites with forcelogin&lt;br /&gt;
* MDL-60309 - Boost: Add a setting for background image&lt;br /&gt;
* MDL-56751 - Create new security setting to configure the expiration time of tokens created via login/token.php or tool/mobile/launch.php&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=361784 MSA-17-0021] Students can find out email addresses of other students in the same course&lt;br /&gt;
&lt;br /&gt;
This list only includes security issues fixed after 3.3.2 release. Refer to other [[Releases|release notes]] for security issues fixed in earlier releases.&lt;br /&gt;
&lt;br /&gt;
===For developers===&lt;br /&gt;
&lt;br /&gt;
* MDL-60611 - Upgrade PHPUnit to 6.4 to ensure compatibility with PHP 7.2 - [https://docs.moodle.org/dev/Writing_PHPUnit_tests#Upgrading_unit_tests_to_work_with_Moodle_3.4_and_up_.28PHPUnit_6.29 may require changes in unittests].&lt;br /&gt;
* MDL-58948 - Compatibility with chrome mink driver&lt;br /&gt;
* MDL-53169 - Provide a way to retrieve all courses a user can potentially access.&lt;br /&gt;
* MDL-59459 - Global Search: Increase file indexing coverage&lt;br /&gt;
* MDL-58957 - Global search: Make it possible to search blocks. See the new [https://docs.moodle.org/dev/Search_API#Base_class \core_search\base_block class].&lt;br /&gt;
* MDL-53240 - [[lib/formslib.php Form Definition#filetypes|Form element]] and admin setting type to choose file types and type groups&lt;br /&gt;
* MDL-53848 - Formslib - add function to $mform that makes it possible to hide form elements dependent on selected values&lt;br /&gt;
* MDL-60234 - Add possibility to disable admin warning if a development libs directory exists&lt;br /&gt;
* MDL-57886 - Plagiarism: onlinetext submission should pass raw submissiontext to plagiarism get_links()&lt;br /&gt;
&lt;br /&gt;
==== Upgrading plugins ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Check for changes in core APIs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Read lib/upgrade.txt to check for the deprecations and core API changes, make sure you applied them to your plugin. Note that entries there are not sorted by priority but rather by integration time. Below is the list of upgrade.txt files that contain information about upgrading from Moodle 3.3 to Moodle 3.4 (note that if you upgrade from earlier versions there may be more files):&lt;br /&gt;
&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/lib/upgrade.txt lib/upgrade.txt] changes to various core APIs, deprecations, functions removal&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/calendar/upgrade.txt calendar/upgrade.txt] changes to Calendar API&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/search/upgrade.txt search/upgrade.txt] changes to Global search API&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/webservice/upgrade.txt webservice/upgrade.txt] changes to WebServices API&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Check for changes in the API of your plugin type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Below is the list of plugin types that had API changes between Moodle 3.3 and 3.4:&lt;br /&gt;
&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/blocks/upgrade.txt blocks/upgrade.txt] Block plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/dataformat/upgrade.txt dataformat/upgrade.txt] Dataformat plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/enrol/upgrade.txt enrol/upgrade.txt] Enrolment method plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/mod/upgrade.txt mod/upgrade.txt] Activity module plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/plagiarism/upgrade.txt plagiarism/upgrade.txt] Plagiarism plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/repository/upgrade.txt repository/upgrade.txt] Repository plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/theme/upgrade.txt theme/upgrade.txt] Themes&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/user/profile/field/upgrade.txt user/profile/field/upgrade.txt] User profile fields&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Check for changes in the depended plugins&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If your plugin depends on another plugin or calls methods from another plugin, read upgrade.txt in this plugin directory (if it exists). Below is the list of standard plugins that had changes between Moodle 3.3 and 3.4:&lt;br /&gt;
&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/admin/tool/log/store/database/upgrade.txt logstore_database],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/admin/tool/mobile/upgrade.txt tool_mobile],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/auth/ldap/upgrade.txt auth_ldap],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/blocks/calendar_upcoming/upgrade.txt block_calendar_upcoming],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/lib/editor/atto/upgrade.txt editor_atto],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/assign/upgrade.txt mod_assign],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/data/upgrade.txt mod_data],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/forum/upgrade.txt mod_forum],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/glossary/upgrade.txt mod_glossary],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/lesson/upgrade.txt mod_lesson],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/lti/upgrade.txt mod_lti],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/workshop/upgrade.txt mod_workshop],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/theme/boost/upgrade.txt theme_boost]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Do a smoke test of your plugin with developer debugging mode&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Run all behat and phpunit tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.3 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.4]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.4]]&lt;br /&gt;
[[es:Notas de Moodle 3.4]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=53134</id>
		<title>Git for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=53134"/>
		<updated>2017-10-24T22:04:07Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Replaced &amp;quot;nasties&amp;quot; according to https://tracker.moodle.org/browse/MDL-57976?focusedCommentId=485633&amp;amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-485633&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for helping you get started on Moodle development with Git. For further details of Git, see [[:Category:Git]].&lt;br /&gt;
&lt;br /&gt;
== General workflow ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A reasonable knowledge of the Git basics is a good idea before you start to use it for development. If you are new to Git, you are encouraged to go to &#039;See also&#039; for some more general reading.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:git-pushpull-model.png|right|thumb|400px|Moodle development workflow with Git]]&lt;br /&gt;
Detailed explanation of the workflow can be found in the [[Process]] page. In short, the Moodle development with Git looks like this:&lt;br /&gt;
&lt;br /&gt;
* You as the contributor commit changes into your personal repository at your computer&lt;br /&gt;
* You push the changes into your public repository and publish links to your changes in the Moodle Tracker&lt;br /&gt;
* You request a peer review of your code from another developer&lt;br /&gt;
* When peer reviewer is happy they submit issue for integration&lt;br /&gt;
* Moodle integrators pull the changes from your public repository and if they like them, they put them into Moodle integration repository&lt;br /&gt;
* The integrated change is tested and finally pushed into Moodle production repository&lt;br /&gt;
* You update your local repository with all changes from the production repository and the next cycle may start again&lt;br /&gt;
&lt;br /&gt;
This workflow runs in roughly weekly cycles. The integration happens on Monday and Tuesday and the testing on Wednesday. On Thursday (or Friday if testing takes too long), the production repository moodle.git is usually updated with changes from the last development week.&lt;br /&gt;
&lt;br /&gt;
Most Moodle developers have their public repositories hosted at [http://github.com/ Github]. Alternatively you may want to try [http://gitorious.org Gitorious] or the legendary [http://repo.or.cz repo.or.cz]. In the examples in this guide we assume you&#039;ll set up your public repository at Github.&lt;br /&gt;
&lt;br /&gt;
When you first register on tracker you can not assign issues to yourself or send them for peer review. You will be added to the developers group after your first bug fix is integrated. Before that just comment on the issue with a link to your branch and component lead or another developer will send issue for peer review for you.&lt;br /&gt;
&lt;br /&gt;
== Installing Git on your computer ==&lt;br /&gt;
&lt;br /&gt;
Install Git on your computer. Most Linux distributions have Git available as a package to install. On Debian/Ubuntu, type &#039;&#039;&#039;&#039;sudo apt-get install git&#039;&#039;&#039;&#039; on the terminal. If you are on Mac, [http://code.google.com/p/git-osx-installer/ git-osx-installer] installs it in a few clicks. &lt;br /&gt;
&lt;br /&gt;
Immediately after the installation, set your name and contact e-mail. The name and e-mail will become part of your commits and they can&#039;t be changed later once your commits are accepted into the Moodle code. Therefore we ask contributors to use their real names written in capital letters, eg &amp;quot;John Smith&amp;quot; and not &amp;quot;john smith&amp;quot; or even &amp;quot;john5677&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
    git config --global user.name &amp;quot;Your Name&amp;quot;&lt;br /&gt;
    git config --global user.email yourmail@domain.tld&lt;br /&gt;
&lt;br /&gt;
Unless you are the repository maintainer, it is wise to set your Git to not push changes in file permissions:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.filemode false&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to verify that the your git installation is not performing any transformation between LFs and CRLFs. All Moodle &#039;&#039;&#039;uses only LFs&#039;&#039;&#039; and you should &#039;&#039;&#039;fetch/edit and push&#039;&#039;&#039; it that way (may need to configure your editor/IDE too). Note that having any &amp;quot;magic&amp;quot; enabled is known to cause [[Common unit test problems#The_test_file_.22evolution.test.22_should_not_contain_section_named_.22.5Blots_of_content.5D.22|problems with unit tests]] execution. So we recommend you to set:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.autocrlf false&lt;br /&gt;
&lt;br /&gt;
== Setting-up the public repository ==&lt;br /&gt;
&lt;br /&gt;
1. Go to [http://github.com/ Github] and create an account.&lt;br /&gt;
&lt;br /&gt;
2. Go to the [http://github.com/moodle/moodle official Moodle Github repository] and click on the Fork button. You now have your own Github Moodle repository.&lt;br /&gt;
&lt;br /&gt;
3. Now you need to set up your SSH public key, so you can push to your Github Moodle repository from your local Moodle repository. On Mac you can go on this [http://help.github.com/mac-key-setup/ Github help page]. If you are on another system, go to your Github administration page, to the section SSH Public Keys, and you should see a link to a help page. Done? Good! That was the most difficult part!&lt;br /&gt;
&lt;br /&gt;
== Setting-up the local repository at your computer  ==&lt;br /&gt;
&lt;br /&gt;
Create a local clone repository of your Github repository. In a terminal:&lt;br /&gt;
&lt;br /&gt;
    git clone git://github.com/YOUR_GITHUB_USERNAME/moodle.git LOCALDIR&lt;br /&gt;
&lt;br /&gt;
    (or:  git clone git@github.com:YOUR_GITHUB_USERNAME/moodle.git LOCALDIR)&lt;br /&gt;
&lt;br /&gt;
This command does several jobs for you. It creates a new folder, initializes an empty Git repository in it, sets your Github repository as the remote repository called &#039;origin&#039; and makes a local checkout of the branch &#039;master&#039; from it. The important point to remember now is that your Github repository is aliased as &#039;origin&#039; for your local clone.&lt;br /&gt;
&lt;br /&gt;
Note that the format of the URL here is important. In the first example, the URL starts &amp;quot;git://github.com&amp;quot; and this will give read-only access to the repository at github.com. If you use this URL, the &amp;quot;git push origin&amp;quot; command that appears later in this document will not work. Therefore, if you want to be able to update the &amp;quot;origin&amp;quot; repository, you should use the URL that starts &amp;quot;git@github.com&amp;quot;, i.e. the second of the two &amp;quot;git clone&amp;quot; commands given above. This will give you read and write access to the repository on github.com.&lt;br /&gt;
&lt;br /&gt;
== Keeping your public repository up-to-date ==&lt;br /&gt;
&lt;br /&gt;
[[image:git-sync-github.png|right|thumb|400px|Fetching changes from upstream and pushing them to github]]&lt;br /&gt;
Your fork at Github is not updated automatically. To keep it synced with the upstream Moodle repository, you have to fetch the recent changes from the official moodle.git and push them to your public repository. To avoid problems with this it is strongly recommended that you never modify the standard Moodle branches. &#039;&#039;Remember: never commit directly into master and MOODLE_xx_STABLE branches.&#039;&#039; In other words, always create topic branches to work on. In Gitspeak, the master branch and MOODLE_xx_STABLE branches should be always fast-forwardable.&lt;br /&gt;
&lt;br /&gt;
To keep your public repository up-to-date, we will register remote repository git://git.moodle.org/moodle.git under &#039;upstream&#039; alias. Then we create a script to be run regularly that fetches changes from the upstream repository and pushes them to your public repository. Note that this procedure will not affect your local working directory.&lt;br /&gt;
&lt;br /&gt;
To register the upstream remote:&lt;br /&gt;
&lt;br /&gt;
    cd moodle&lt;br /&gt;
    git remote add upstream git://git.moodle.org/moodle.git&lt;br /&gt;
&lt;br /&gt;
The following commands can be used to keep the standard Moodle branches at your Github repository synced with the upstream repository. You may wish to store them in a script so that you can run it every week after the upstream repository is updated.&lt;br /&gt;
&lt;br /&gt;
    #!/bin/bash&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    for BRANCH in MOODLE_{19..33}_STABLE master; do&lt;br /&gt;
        git push origin refs/remotes/upstream/$BRANCH:refs/heads/$BRANCH&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
The git-fetch command does not modify your current working dir (your checkout). It just downloads all recent changes from a remote repository and stores them into so called remote-tracking branches. The git-push command takes these remote-tracking branches from upstream and pushes them to Github under the same name. Understanding this fully requires a bit knowledge of Git internals - see gitrevisions(7) man page.&lt;br /&gt;
&lt;br /&gt;
Note there is no need to switch the local branch during this. You can even execute this via cron at your machine. Just note that the upstream repository updates typically just once a week.&lt;br /&gt;
&lt;br /&gt;
=== New branches ===&lt;br /&gt;
&lt;br /&gt;
Occasionally, moodle.org will create a new branch that does not exist in your public (e.g. Github.com) repository. If you try to push this new branch, you will see an error such as the following:&lt;br /&gt;
&lt;br /&gt;
    error: unable to push to unqualified destination: MOODLE_99_STABLE&lt;br /&gt;
    The destination refspec neither matches an existing ref on the remote&lt;br /&gt;
    nor begins with refs/, and we are unable to guess a prefix based on the source ref.&lt;br /&gt;
    error: failed to push some refs to &#039;git@github.com:YOUR_GITHUB_USERNAME/moodle.git&#039;&lt;br /&gt;
&lt;br /&gt;
In the above example, &amp;quot;MOODLE_99_STABLE&amp;quot;, is the name of the new branch that does not exist in your public repository. To fix the error, you need to create the new branch on your public repository, using the following commands, replacing &amp;quot;MOODLE_99_STABLE&amp;quot; with the name of the new branch you wish to create:&lt;br /&gt;
&lt;br /&gt;
    git checkout MOODLE_99_STABLE&lt;br /&gt;
    git push origin MOODLE_99_STABLE:MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
The above code will create a new copy of the &amp;quot;MOODLE_99_STABLE&amp;quot; branch in your local repository. If you do not need to keep a local copy of the new branch - and probably you do not need it, you then can remove it from your local repository as follows:&lt;br /&gt;
&lt;br /&gt;
    git checkout master&lt;br /&gt;
    git branch -D MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
== Preparing a patch ==&lt;br /&gt;
&lt;br /&gt;
As said earlier at this page, you never work on standard Moodle branches directly. Every time you are going to edit something, switch to a local branch. Fork the local branch off the standard branch you think it should be merged to. So if you are working on a patch for 1.9 or 2.0, fork the branch off MOODLE_19_STABLE or MOODLE_20_STABLE, respectively. Patches for the next [[Moodle versions|major version]] should be based on the master branch.&lt;br /&gt;
&lt;br /&gt;
    git checkout -b MDL-xxxxx-short-description-of-the-bug origin/master&lt;br /&gt;
&lt;br /&gt;
Note that if you forget to specify the starting point, the branch is based on the currently checked-out branch. It may not be what you want. It is recommended to always specify the starting point.&lt;br /&gt;
&lt;br /&gt;
To check the current branch, run&lt;br /&gt;
&lt;br /&gt;
    git branch&lt;br /&gt;
&lt;br /&gt;
The current branch is highlighted.&lt;br /&gt;
&lt;br /&gt;
Now go and fix the issue with your favorite IDE. Check the status of the files, view the change to be committed and finally commit the change:&lt;br /&gt;
&lt;br /&gt;
    vim filename.php&lt;br /&gt;
    git status&lt;br /&gt;
    git diff&lt;br /&gt;
    git commit -a&lt;br /&gt;
&lt;br /&gt;
Note that this is safe as the commit is recorded just locally, nothing is sent to any server yet (as it would in CVS). To see history of the commits, use&lt;br /&gt;
&lt;br /&gt;
    git log&lt;br /&gt;
&lt;br /&gt;
Once your local branch contains the change (note that it may consists of several patches) and you are happy with it, publish the branch at your public repository:&lt;br /&gt;
&lt;br /&gt;
    git push origin MDL-xxxxx-short-description-of-the-bug&lt;br /&gt;
&lt;br /&gt;
Now as your branch is published, you can ask Moodle core developers to review it and eventually integrate it into the standard Moodle repository.&lt;br /&gt;
&lt;br /&gt;
=== Changing commit message, reordering and squashing commits ===&lt;br /&gt;
&lt;br /&gt;
It often happens that you made a mistake in your patch or in the commit message and helpful CiBot pointed it out for you. You can &amp;quot;rewrite the history&amp;quot; and change the existing commits.&lt;br /&gt;
&lt;br /&gt;
Option 1. Reset all the changes in the branch and commit again. &lt;br /&gt;
&lt;br /&gt;
    git reset --mixed origin/master&lt;br /&gt;
&lt;br /&gt;
Now all your changes are still present but all commits on top of &amp;quot;master&amp;quot; branch are gone. You can create a new commit&lt;br /&gt;
&lt;br /&gt;
Option 2. Discover &#039;&#039;&#039;git rebase --interactive&#039;&#039;&#039; - this is a powerful tool to change the sequence of commit, change the commit messages, squash commits, etc. We will not cover it here, there are many articles in the Internet about it, for example: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History.&lt;br /&gt;
&lt;br /&gt;
Whatever option you chose, you have &amp;quot;rewritten the history&amp;quot; and you can not simply push the changes to github again because they would need to overwrite the commits that were already pushed. If you try &amp;quot;git push MDL-xxxxx-short-description-of-the-bug&amp;quot; you will get an error message suggesting you to force push. &lt;br /&gt;
To force push the changed commits use:&lt;br /&gt;
&lt;br /&gt;
    git push -f origin MDL-xxxxx-short-description-of-the-bug&lt;br /&gt;
&lt;br /&gt;
If an error occurs because you are still using the git protocol (read only), use this command : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin https://github.com/&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
A prompt will ask for your credentials, if you previously setup your SSH public key you can also use this one : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin git@github.com:&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
=== Checking if a branch has already been merged ===&lt;br /&gt;
&lt;br /&gt;
After some time contributing to Moodle you would have a lot of branches both in your local repository and in your public repository. To prune their list and delete those that were accepted by upstream, use the following&lt;br /&gt;
&lt;br /&gt;
    git fetch upstream                                      (1)&lt;br /&gt;
    git branch --merged upstream/master                     (2)&lt;br /&gt;
    git branch --merged upstream/MOODLE_20_STABLE           (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) fetches the changes from your upstream repository at git.moodle.org (remember that git-fetch does not modify your working dir so it is safe to run it whenever). Command (2) and (3) print all branches that are merged into the upstream master branch and MOODLE_20_STABLE branch, respectively. To delete these local branches, use&lt;br /&gt;
&lt;br /&gt;
    git branch -d MDL-xxxxx-accepted-branch&lt;br /&gt;
&lt;br /&gt;
The similar approach can be used to check the branches published at your origin repository at github.com&lt;br /&gt;
&lt;br /&gt;
    git fetch origin                                        (1)&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    git branch -r --merged upstream/master                  (2)&lt;br /&gt;
    git branch -r --merged upstream/MOODLE_20_STABLE        (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) makes sure that you have all your branches from github.com recorded as the remote tracking branch locally. Commands (2) and (3) work the same as in the previous example but they list remote tracking branches only ([http://www.kernel.org/pub/software/scm/git/docs/git-branch.html see -r param]). To delete a branch at github.com, use&lt;br /&gt;
&lt;br /&gt;
    git push origin :MDL-xxxx-branch-to-delete&lt;br /&gt;
&lt;br /&gt;
This syntax may look weird to you. However it is pretty logical. The general syntax of the git-push command is&lt;br /&gt;
&lt;br /&gt;
    git push &amp;lt;repository&amp;gt; &amp;lt;source ref&amp;gt;:&amp;lt;target ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so deleting a remote branch can be understood as pushing an &amp;quot;empty (null) reference&amp;quot; to it.&lt;br /&gt;
&lt;br /&gt;
== Peer-reviewing someone else&#039;s code ==&lt;br /&gt;
&lt;br /&gt;
To review a branch that someone else pushed into their public repository, you do not need to register a new remote (unless you work with such repository frequently, of course). Let us imagine your friend Alice pushed a work-in-progress branch called &#039;wip-feature&#039; into her Github repository and asked you to review it. You need to know the read-only address of the repository and the name of the branch.&lt;br /&gt;
&lt;br /&gt;
    git fetch git://github.com/alice/moodle.git wip-feature&lt;br /&gt;
&lt;br /&gt;
This will download all required data and will keep the pointer to the tip of the wip-feature branch in a local symbolic reference FETCH_HEAD. To see what&#039;s there on that branch, use&lt;br /&gt;
&lt;br /&gt;
    git log -p FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see how a particular file looks at Alice&#039;s branch&lt;br /&gt;
&lt;br /&gt;
    git show FETCH_HEAD:admin/blocks.php&lt;br /&gt;
&lt;br /&gt;
To create a new local branch called &#039;alice-wip-feature&#039; containing the work by Alice, use&lt;br /&gt;
&lt;br /&gt;
    git checkout -b alice-wip-feature FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To merge Alice&#039;s work into your current branch:&lt;br /&gt;
&lt;br /&gt;
    git merge FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see what would be merged into the current branch without actually modifying anything:&lt;br /&gt;
&lt;br /&gt;
    git diff ...FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
Once you are all set and reviewing code, this [[Peer_reviewing_checklist|checklist]] should prove to be useful.&lt;br /&gt;
&lt;br /&gt;
== Rebasing a branch ==&lt;br /&gt;
&lt;br /&gt;
Rebasing is a process when you cut off the branch from its current start point and transplant it to another point. Let us assume the following history exists:&lt;br /&gt;
&lt;br /&gt;
          A---B---C topic&lt;br /&gt;
         /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
From this point, the result of the command:&lt;br /&gt;
&lt;br /&gt;
    git rebase master topic&lt;br /&gt;
&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
                  A&#039;--B&#039;--C&#039; topic&lt;br /&gt;
                 /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
and would end with &#039;topic&#039; being your current branch.&lt;br /&gt;
&lt;br /&gt;
You may be asked to rebase your branch submitted for the integration if the submitted branch was based on an outdated commit. The typical case is if you create a new branch as a fork off the upstream master branch on Tuesday. Then on Wednesday, the upstream master branch grows as all changes from the last integration cycle are merged to it. To make diff easy on Github for next weekly pull request review, you want to rebase your branch against the updated master.&lt;br /&gt;
&lt;br /&gt;
    git rebase master MDL-xxxxx-topic-branch&lt;br /&gt;
&lt;br /&gt;
Note that rebasing effectively rewrites the history of the branch. &#039;&#039;&#039;Do not rebase the branch if there is a chance that somebody has already forked it and based their own branch on it.&#039;&#039;&#039; For this reason, many Git tutorials discourage from rebasing any branch that has been published. However in Moodle, all branches submitted for integration are potential subject of rebase (even though we try to not to do it often) and you should not base your own branches on them.&lt;br /&gt;
&lt;br /&gt;
=== Conflicts during rebase ===&lt;br /&gt;
&lt;br /&gt;
During the rebase procedure, conflicts may appear. git-status commands reports the conflicted files. Explore them carefully and fix them in your editor (like you would do with CVS). Then add the files with &#039;git add&#039; command and continue.&lt;br /&gt;
&lt;br /&gt;
    vim conflicted.php&lt;br /&gt;
    git add conflicted.php&lt;br /&gt;
    git rebase --continue&lt;br /&gt;
&lt;br /&gt;
== Applying changes from one branch to another ==&lt;br /&gt;
&lt;br /&gt;
Most bugs are fixed at a stable branch (like MOODLE_20_STABLE) and the fix must be prepared for other branches, too (like MOODLE_21_STABLE and the main development branch - master). In Moodle, we do not merge stable branches into the master one. So usually the contributor prepares at least two branches - with the fix for the stable branch(es) and with the fix for the master branch.&lt;br /&gt;
&lt;br /&gt;
If you have a patch prepared on a local branch (let us say MDL-xxxx-topic_20_STABLE), it is possible to re-apply it to another branch.&lt;br /&gt;
&lt;br /&gt;
=== Cherry-picking a single commit ===&lt;br /&gt;
&lt;br /&gt;
Let us have two local Git repositories ~/public_html/moodle21 containing local installation of Moodle 2.1 and ~/public_html/moodledev with the local installation of most recent development version of Moodle. They both use your public repository at github.com as the origin. You have a branch in moodle21 called MDL-xxxx-topic_21_STABLE that was forked off MOODLE_21_STABLE. It contains one commit. Now you want to re-apply this commit to a branch MDL-xxxx-topic in moodledev.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master            (1)&lt;br /&gt;
    git fetch ../moodle21 MDL-xxxx-topic_21_STABLE          (2)&lt;br /&gt;
    git cherry-pick FETCH_HEAD                              (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) creates new local branch forked off the master. The command (2) fetches all data needed to re-apply the topic branch and stores the pointer to the tip of that branch to FETCH_HEAD symbolic reference. The command (3) picks the tip of the branch (the top-most commit on it) and tries to apply it on the current branch.&lt;br /&gt;
There is also a variant of the cherry-pick command that supports multiple commits, shortly (see its man page for details): &amp;lt;code bash&amp;gt;$ git cherry-pick A^..B&amp;lt;/code&amp;gt; if you want to include from A - see &#039;&#039;&#039;^&#039;&#039;&#039; - to B, A should be older than B. We will use another approach for cherry-picking multiple commits.&lt;br /&gt;
&lt;br /&gt;
=== Applying a set of patches ===&lt;br /&gt;
&lt;br /&gt;
If the branch MDL-xxxx-topic_21_STABLE from the previous example consists of several commits, it may be easier to use git-format-patch and git-am combo to re-apply the whole set of patches (aka patchset). Firstly you will export all commits from the topic branch to files.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodle21&lt;br /&gt;
    mkdir .patches&lt;br /&gt;
    git format-patch -o .patches MOODLE_21_STABLE..MDL-xxxx-topic_21_STABLE         (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) takes all commits from the topic branch that are not in MOODLE_21_STABLE and exports them one by one to the output directory .patches. Look at the generated files. They contain the patch itself (in diff format) and additional information about the commit. You could eg send these files by email to a friend of yours for peer-review. We will use them in another repository.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master&lt;br /&gt;
    git am -3 ../moodle21/.patches/*                        (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) applies all the files from the .patches directory. When a patch does not apply cleanly, the command tries fall back on 3-way merge (see the -3 parameter). If conflicts occur during the procedure, you can either deal with them and then use `git am --continue` or abort the whole procedure with `git am --abort`.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
; Moodle forum discussions&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=168094 GIT help needed]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=165236 Best way to manage CONTRIB code with GIT]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167063 Handy Git tip for tracking 3rd-party modules and plugins]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167730 Moodle Git repositories]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=183409 Git help!! I don&#039;t understand rebase enough...]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=217617 add MOODLE_24_STABLE to github.com repository]&lt;br /&gt;
&lt;br /&gt;
; External resources &lt;br /&gt;
* [http://www.kernel.org/pub/software/scm/git/docs/everyday.html Everyday GIT With 20 Commands Or So]&lt;br /&gt;
* [http://gitref.org/ Git Reference]&lt;br /&gt;
* [http://progit.org/book/ Pro Git book]&lt;br /&gt;
* [http://vimeo.com/14629850 Getting git by Scott Chacon] - an recording of an excellent 1-hour presentation that introducing git, including a simple introduction to what is going on under the hood.&lt;br /&gt;
* [http://tjhunt.blogspot.co.uk/2012/03/fixing-bug-in-moodle-core-mechanics.html Tim Hunt&#039;s blog: Fixing a bug in Moodle core: the mechanics]&lt;br /&gt;
&lt;br /&gt;
[[Category:Git]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発者用Git]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=53133</id>
		<title>Git for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=53133"/>
		<updated>2017-10-24T22:00:33Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Provide an example according to https://tracker.moodle.org/browse/MDL-57976?focusedCommentId=485633&amp;amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-485633&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for helping you get started on Moodle development with Git. For further details of Git, see [[:Category:Git]].&lt;br /&gt;
&lt;br /&gt;
== General workflow ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A reasonable knowledge of the Git basics is a good idea before you start to use it for development. If you are new to Git, you are encouraged to go to &#039;See also&#039; for some more general reading.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:git-pushpull-model.png|right|thumb|400px|Moodle development workflow with Git]]&lt;br /&gt;
Detailed explanation of the workflow can be found in the [[Process]] page. In short, the Moodle development with Git looks like this:&lt;br /&gt;
&lt;br /&gt;
* You as the contributor commit changes into your personal repository at your computer&lt;br /&gt;
* You push the changes into your public repository and publish links to your changes in the Moodle Tracker&lt;br /&gt;
* You request a peer review of your code from another developer&lt;br /&gt;
* When peer reviewer is happy they submit issue for integration&lt;br /&gt;
* Moodle integrators pull the changes from your public repository and if they like them, they put them into Moodle integration repository&lt;br /&gt;
* The integrated change is tested and finally pushed into Moodle production repository&lt;br /&gt;
* You update your local repository with all changes from the production repository and the next cycle may start again&lt;br /&gt;
&lt;br /&gt;
This workflow runs in roughly weekly cycles. The integration happens on Monday and Tuesday and the testing on Wednesday. On Thursday (or Friday if testing takes too long), the production repository moodle.git is usually updated with changes from the last development week.&lt;br /&gt;
&lt;br /&gt;
Most Moodle developers have their public repositories hosted at [http://github.com/ Github]. Alternatively you may want to try [http://gitorious.org Gitorious] or the legendary [http://repo.or.cz repo.or.cz]. In the examples in this guide we assume you&#039;ll set up your public repository at Github.&lt;br /&gt;
&lt;br /&gt;
When you first register on tracker you can not assign issues to yourself or send them for peer review. You will be added to the developers group after your first bug fix is integrated. Before that just comment on the issue with a link to your branch and component lead or another developer will send issue for peer review for you.&lt;br /&gt;
&lt;br /&gt;
== Installing Git on your computer ==&lt;br /&gt;
&lt;br /&gt;
Install Git on your computer. Most Linux distributions have Git available as a package to install. On Debian/Ubuntu, type &#039;&#039;&#039;&#039;sudo apt-get install git&#039;&#039;&#039;&#039; on the terminal. If you are on Mac, [http://code.google.com/p/git-osx-installer/ git-osx-installer] installs it in a few clicks. &lt;br /&gt;
&lt;br /&gt;
Immediately after the installation, set your name and contact e-mail. The name and e-mail will become part of your commits and they can&#039;t be changed later once your commits are accepted into the Moodle code. Therefore we ask contributors to use their real names written in capital letters, eg &amp;quot;John Smith&amp;quot; and not &amp;quot;john smith&amp;quot; or even &amp;quot;john5677&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
    git config --global user.name &amp;quot;Your Name&amp;quot;&lt;br /&gt;
    git config --global user.email yourmail@domain.tld&lt;br /&gt;
&lt;br /&gt;
Unless you are the repository maintainer, it is wise to set your Git to not push changes in file permissions:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.filemode false&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to verify that the your git installation is not performing any transformation between LFs and CRLFs. All Moodle &#039;&#039;&#039;uses only LFs&#039;&#039;&#039; and you should &#039;&#039;&#039;fetch/edit and push&#039;&#039;&#039; it that way (may need to configure your editor/IDE too). Note that having any &amp;quot;magic&amp;quot; enabled is known to cause [[Common unit test problems#The_test_file_.22evolution.test.22_should_not_contain_section_named_.22.5Blots_of_content.5D.22|problems with unit tests]] execution. So we recommend you to set:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.autocrlf false&lt;br /&gt;
&lt;br /&gt;
== Setting-up the public repository ==&lt;br /&gt;
&lt;br /&gt;
1. Go to [http://github.com/ Github] and create an account.&lt;br /&gt;
&lt;br /&gt;
2. Go to the [http://github.com/moodle/moodle official Moodle Github repository] and click on the Fork button. You now have your own Github Moodle repository.&lt;br /&gt;
&lt;br /&gt;
3. Now you need to set up your SSH public key, so you can push to your Github Moodle repository from your local Moodle repository. On Mac you can go on this [http://help.github.com/mac-key-setup/ Github help page]. If you are on another system, go to your Github administration page, to the section SSH Public Keys, and you should see a link to a help page. Done? Good! That was the most difficult part!&lt;br /&gt;
&lt;br /&gt;
== Setting-up the local repository at your computer  ==&lt;br /&gt;
&lt;br /&gt;
Create a local clone repository of your Github repository. In a terminal:&lt;br /&gt;
&lt;br /&gt;
    git clone git://github.com/YOUR_GITHUB_USERNAME/moodle.git LOCALDIR&lt;br /&gt;
&lt;br /&gt;
    (or:  git clone git@github.com:YOUR_GITHUB_USERNAME/moodle.git LOCALDIR)&lt;br /&gt;
&lt;br /&gt;
This command does several jobs for you. It creates a new folder, initializes an empty Git repository in it, sets your Github repository as the remote repository called &#039;origin&#039; and makes a local checkout of the branch &#039;master&#039; from it. The important point to remember now is that your Github repository is aliased as &#039;origin&#039; for your local clone.&lt;br /&gt;
&lt;br /&gt;
Note that the format of the URL here is important. In the first example, the URL starts &amp;quot;git://github.com&amp;quot; and this will give read-only access to the repository at github.com. If you use this URL, the &amp;quot;git push origin&amp;quot; command that appears later in this document will not work. Therefore, if you want to be able to update the &amp;quot;origin&amp;quot; repository, you should use the URL that starts &amp;quot;git@github.com&amp;quot;, i.e. the second of the two &amp;quot;git clone&amp;quot; commands given above. This will give you read and write access to the repository on github.com.&lt;br /&gt;
&lt;br /&gt;
== Keeping your public repository up-to-date ==&lt;br /&gt;
&lt;br /&gt;
[[image:git-sync-github.png|right|thumb|400px|Fetching changes from upstream and pushing them to github]]&lt;br /&gt;
Your fork at Github is not updated automatically. To keep it synced with the upstream Moodle repository, you have to fetch the recent changes from the official moodle.git and push them to your public repository. To avoid problems with this it is strongly recommended that you never modify the standard Moodle branches. &#039;&#039;Remember: never commit directly into master and MOODLE_xx_STABLE branches.&#039;&#039; In other words, always create topic branches to work on. In Gitspeak, the master branch and MOODLE_xx_STABLE branches should be always fast-forwardable.&lt;br /&gt;
&lt;br /&gt;
To keep your public repository up-to-date, we will register remote repository git://git.moodle.org/moodle.git under &#039;upstream&#039; alias. Then we create a script to be run regularly that fetches changes from the upstream repository and pushes them to your public repository. Note that this procedure will not affect your local working directory.&lt;br /&gt;
&lt;br /&gt;
To register the upstream remote:&lt;br /&gt;
&lt;br /&gt;
    cd moodle&lt;br /&gt;
    git remote add upstream git://git.moodle.org/moodle.git&lt;br /&gt;
&lt;br /&gt;
The following commands can be used to keep the standard Moodle branches at your Github repository synced with the upstream repository. You may wish to store them in a script so that you can run it every week after the upstream repository is updated.&lt;br /&gt;
&lt;br /&gt;
    #!/bin/bash&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    for BRANCH in MOODLE_{19..33}_STABLE master; do&lt;br /&gt;
        git push origin refs/remotes/upstream/$BRANCH:refs/heads/$BRANCH&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
The git-fetch command does not modify your current working dir (your checkout). It just downloads all recent changes from a remote repository and stores them into so called remote-tracking branches. The git-push command takes these remote-tracking branches from upstream and pushes them to Github under the same name. Understanding this fully requires a bit knowledge of Git internals - see gitrevisions(7) man page.&lt;br /&gt;
&lt;br /&gt;
Note there is no need to switch the local branch during this. You can even execute this via cron at your machine. Just note that the upstream repository updates typically just once a week.&lt;br /&gt;
&lt;br /&gt;
=== New branches ===&lt;br /&gt;
&lt;br /&gt;
Occasionally, moodle.org will create a new branch that does not exist in your public (e.g. Github.com) repository. If you try to push this new branch, you will see an error such as the following:&lt;br /&gt;
&lt;br /&gt;
    error: unable to push to unqualified destination: MOODLE_99_STABLE&lt;br /&gt;
    The destination refspec neither matches an existing ref on the remote&lt;br /&gt;
    nor begins with refs/, and we are unable to guess a prefix based on the source ref.&lt;br /&gt;
    error: failed to push some refs to &#039;git@github.com:YOUR_GITHUB_USERNAME/moodle.git&#039;&lt;br /&gt;
&lt;br /&gt;
In the above example, &amp;quot;MOODLE_99_STABLE&amp;quot;, is the name of the new branch that does not exist in your public repository. To fix the error, you need to create the new branch on your public repository, using the following commands, replacing &amp;quot;MOODLE_99_STABLE&amp;quot; with the name of the new branch you wish to create:&lt;br /&gt;
&lt;br /&gt;
    git checkout MOODLE_99_STABLE&lt;br /&gt;
    git push origin MOODLE_99_STABLE:MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
The above code will create a new copy of the &amp;quot;MOODLE_99_STABLE&amp;quot; branch in your local repository. If you do not need to keep a local copy of the new branch - and probably you do not need it, you then can remove it from your local repository as follows:&lt;br /&gt;
&lt;br /&gt;
    git checkout master&lt;br /&gt;
    git branch -D MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
== Preparing a patch ==&lt;br /&gt;
&lt;br /&gt;
As said earlier at this page, you never work on standard Moodle branches directly. Every time you are going to edit something, switch to a local branch. Fork the local branch off the standard branch you think it should be merged to. So if you are working on a patch for 1.9 or 2.0, fork the branch off MOODLE_19_STABLE or MOODLE_20_STABLE, respectively. Patches for the next [[Moodle versions|major version]] should be based on the master branch.&lt;br /&gt;
&lt;br /&gt;
    git checkout -b MDL-xxxxx-nasty-bug origin/master&lt;br /&gt;
&lt;br /&gt;
Note that if you forget to specify the starting point, the branch is based on the currently checked-out branch. It may not be what you want. It is recommended to always specify the starting point.&lt;br /&gt;
&lt;br /&gt;
To check the current branch, run&lt;br /&gt;
&lt;br /&gt;
    git branch&lt;br /&gt;
&lt;br /&gt;
The current branch is highlighted.&lt;br /&gt;
&lt;br /&gt;
Now go and fix the issue with your favorite IDE. Check the status of the files, view the change to be committed and finally commit the change:&lt;br /&gt;
&lt;br /&gt;
    vim filename.php&lt;br /&gt;
    git status&lt;br /&gt;
    git diff&lt;br /&gt;
    git commit -a&lt;br /&gt;
&lt;br /&gt;
Note that this is safe as the commit is recorded just locally, nothing is sent to any server yet (as it would in CVS). To see history of the commits, use&lt;br /&gt;
&lt;br /&gt;
    git log&lt;br /&gt;
&lt;br /&gt;
Once your local branch contains the change (note that it may consists of several patches) and you are happy with it, publish the branch at your public repository:&lt;br /&gt;
&lt;br /&gt;
    git push origin MDL-xxxxx-nasty-bug&lt;br /&gt;
&lt;br /&gt;
Now as your branch is published, you can ask Moodle core developers to review it and eventually integrate it into the standard Moodle repository.&lt;br /&gt;
&lt;br /&gt;
=== Changing commit message, reordering and squashing commits ===&lt;br /&gt;
&lt;br /&gt;
It often happens that you made a mistake in your patch or in the commit message and helpful CiBot pointed it out for you. You can &amp;quot;rewrite the history&amp;quot; and change the existing commits.&lt;br /&gt;
&lt;br /&gt;
Option 1. Reset all the changes in the branch and commit again. &lt;br /&gt;
&lt;br /&gt;
    git reset --mixed origin/master&lt;br /&gt;
&lt;br /&gt;
Now all your changes are still present but all commits on top of &amp;quot;master&amp;quot; branch are gone. You can create a new commit&lt;br /&gt;
&lt;br /&gt;
Option 2. Discover &#039;&#039;&#039;git rebase --interactive&#039;&#039;&#039; - this is a powerful tool to change the sequence of commit, change the commit messages, squash commits, etc. We will not cover it here, there are many articles in the Internet about it, for example: https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History.&lt;br /&gt;
&lt;br /&gt;
Whatever option you chose, you have &amp;quot;rewritten the history&amp;quot; and you can not simply push the changes to github again because they would need to overwrite the commits that were already pushed. If you try &amp;quot;git push MDL-xxxxx-nasty-bug&amp;quot; you will get an error message suggesting you to force push. &lt;br /&gt;
To force push the changed commits use:&lt;br /&gt;
&lt;br /&gt;
    git push -f origin MDL-xxxxx-nasty-bug&lt;br /&gt;
&lt;br /&gt;
If an error occurs because you are still using the git protocol (read only), use this command : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin https://github.com/&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
A prompt will ask for your credentials, if you previously setup your SSH public key you can also use this one : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin git@github.com:&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
=== Checking if a branch has already been merged ===&lt;br /&gt;
&lt;br /&gt;
After some time contributing to Moodle you would have a lot of branches both in your local repository and in your public repository. To prune their list and delete those that were accepted by upstream, use the following&lt;br /&gt;
&lt;br /&gt;
    git fetch upstream                                      (1)&lt;br /&gt;
    git branch --merged upstream/master                     (2)&lt;br /&gt;
    git branch --merged upstream/MOODLE_20_STABLE           (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) fetches the changes from your upstream repository at git.moodle.org (remember that git-fetch does not modify your working dir so it is safe to run it whenever). Command (2) and (3) print all branches that are merged into the upstream master branch and MOODLE_20_STABLE branch, respectively. To delete these local branches, use&lt;br /&gt;
&lt;br /&gt;
    git branch -d MDL-xxxxx-accepted-branch&lt;br /&gt;
&lt;br /&gt;
The similar approach can be used to check the branches published at your origin repository at github.com&lt;br /&gt;
&lt;br /&gt;
    git fetch origin                                        (1)&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    git branch -r --merged upstream/master                  (2)&lt;br /&gt;
    git branch -r --merged upstream/MOODLE_20_STABLE        (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) makes sure that you have all your branches from github.com recorded as the remote tracking branch locally. Commands (2) and (3) work the same as in the previous example but they list remote tracking branches only ([http://www.kernel.org/pub/software/scm/git/docs/git-branch.html see -r param]). To delete a branch at github.com, use&lt;br /&gt;
&lt;br /&gt;
    git push origin :MDL-xxxx-branch-to-delete&lt;br /&gt;
&lt;br /&gt;
This syntax may look weird to you. However it is pretty logical. The general syntax of the git-push command is&lt;br /&gt;
&lt;br /&gt;
    git push &amp;lt;repository&amp;gt; &amp;lt;source ref&amp;gt;:&amp;lt;target ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so deleting a remote branch can be understood as pushing an &amp;quot;empty (null) reference&amp;quot; to it.&lt;br /&gt;
&lt;br /&gt;
== Peer-reviewing someone else&#039;s code ==&lt;br /&gt;
&lt;br /&gt;
To review a branch that someone else pushed into their public repository, you do not need to register a new remote (unless you work with such repository frequently, of course). Let us imagine your friend Alice pushed a work-in-progress branch called &#039;wip-feature&#039; into her Github repository and asked you to review it. You need to know the read-only address of the repository and the name of the branch.&lt;br /&gt;
&lt;br /&gt;
    git fetch git://github.com/alice/moodle.git wip-feature&lt;br /&gt;
&lt;br /&gt;
This will download all required data and will keep the pointer to the tip of the wip-feature branch in a local symbolic reference FETCH_HEAD. To see what&#039;s there on that branch, use&lt;br /&gt;
&lt;br /&gt;
    git log -p FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see how a particular file looks at Alice&#039;s branch&lt;br /&gt;
&lt;br /&gt;
    git show FETCH_HEAD:admin/blocks.php&lt;br /&gt;
&lt;br /&gt;
To create a new local branch called &#039;alice-wip-feature&#039; containing the work by Alice, use&lt;br /&gt;
&lt;br /&gt;
    git checkout -b alice-wip-feature FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To merge Alice&#039;s work into your current branch:&lt;br /&gt;
&lt;br /&gt;
    git merge FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see what would be merged into the current branch without actually modifying anything:&lt;br /&gt;
&lt;br /&gt;
    git diff ...FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
Once you are all set and reviewing code, this [[Peer_reviewing_checklist|checklist]] should prove to be useful.&lt;br /&gt;
&lt;br /&gt;
== Rebasing a branch ==&lt;br /&gt;
&lt;br /&gt;
Rebasing is a process when you cut off the branch from its current start point and transplant it to another point. Let us assume the following history exists:&lt;br /&gt;
&lt;br /&gt;
          A---B---C topic&lt;br /&gt;
         /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
From this point, the result of the command:&lt;br /&gt;
&lt;br /&gt;
    git rebase master topic&lt;br /&gt;
&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
                  A&#039;--B&#039;--C&#039; topic&lt;br /&gt;
                 /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
and would end with &#039;topic&#039; being your current branch.&lt;br /&gt;
&lt;br /&gt;
You may be asked to rebase your branch submitted for the integration if the submitted branch was based on an outdated commit. The typical case is if you create a new branch as a fork off the upstream master branch on Tuesday. Then on Wednesday, the upstream master branch grows as all changes from the last integration cycle are merged to it. To make diff easy on Github for next weekly pull request review, you want to rebase your branch against the updated master.&lt;br /&gt;
&lt;br /&gt;
    git rebase master MDL-xxxxx-topic-branch&lt;br /&gt;
&lt;br /&gt;
Note that rebasing effectively rewrites the history of the branch. &#039;&#039;&#039;Do not rebase the branch if there is a chance that somebody has already forked it and based their own branch on it.&#039;&#039;&#039; For this reason, many Git tutorials discourage from rebasing any branch that has been published. However in Moodle, all branches submitted for integration are potential subject of rebase (even though we try to not to do it often) and you should not base your own branches on them.&lt;br /&gt;
&lt;br /&gt;
=== Conflicts during rebase ===&lt;br /&gt;
&lt;br /&gt;
During the rebase procedure, conflicts may appear. git-status commands reports the conflicted files. Explore them carefully and fix them in your editor (like you would do with CVS). Then add the files with &#039;git add&#039; command and continue.&lt;br /&gt;
&lt;br /&gt;
    vim conflicted.php&lt;br /&gt;
    git add conflicted.php&lt;br /&gt;
    git rebase --continue&lt;br /&gt;
&lt;br /&gt;
== Applying changes from one branch to another ==&lt;br /&gt;
&lt;br /&gt;
Most bugs are fixed at a stable branch (like MOODLE_20_STABLE) and the fix must be prepared for other branches, too (like MOODLE_21_STABLE and the main development branch - master). In Moodle, we do not merge stable branches into the master one. So usually the contributor prepares at least two branches - with the fix for the stable branch(es) and with the fix for the master branch.&lt;br /&gt;
&lt;br /&gt;
If you have a patch prepared on a local branch (let us say MDL-xxxx-topic_20_STABLE), it is possible to re-apply it to another branch.&lt;br /&gt;
&lt;br /&gt;
=== Cherry-picking a single commit ===&lt;br /&gt;
&lt;br /&gt;
Let us have two local Git repositories ~/public_html/moodle21 containing local installation of Moodle 2.1 and ~/public_html/moodledev with the local installation of most recent development version of Moodle. They both use your public repository at github.com as the origin. You have a branch in moodle21 called MDL-xxxx-topic_21_STABLE that was forked off MOODLE_21_STABLE. It contains one commit. Now you want to re-apply this commit to a branch MDL-xxxx-topic in moodledev.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master            (1)&lt;br /&gt;
    git fetch ../moodle21 MDL-xxxx-topic_21_STABLE          (2)&lt;br /&gt;
    git cherry-pick FETCH_HEAD                              (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) creates new local branch forked off the master. The command (2) fetches all data needed to re-apply the topic branch and stores the pointer to the tip of that branch to FETCH_HEAD symbolic reference. The command (3) picks the tip of the branch (the top-most commit on it) and tries to apply it on the current branch.&lt;br /&gt;
There is also a variant of the cherry-pick command that supports multiple commits, shortly (see its man page for details): &amp;lt;code bash&amp;gt;$ git cherry-pick A^..B&amp;lt;/code&amp;gt; if you want to include from A - see &#039;&#039;&#039;^&#039;&#039;&#039; - to B, A should be older than B. We will use another approach for cherry-picking multiple commits.&lt;br /&gt;
&lt;br /&gt;
=== Applying a set of patches ===&lt;br /&gt;
&lt;br /&gt;
If the branch MDL-xxxx-topic_21_STABLE from the previous example consists of several commits, it may be easier to use git-format-patch and git-am combo to re-apply the whole set of patches (aka patchset). Firstly you will export all commits from the topic branch to files.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodle21&lt;br /&gt;
    mkdir .patches&lt;br /&gt;
    git format-patch -o .patches MOODLE_21_STABLE..MDL-xxxx-topic_21_STABLE         (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) takes all commits from the topic branch that are not in MOODLE_21_STABLE and exports them one by one to the output directory .patches. Look at the generated files. They contain the patch itself (in diff format) and additional information about the commit. You could eg send these files by email to a friend of yours for peer-review. We will use them in another repository.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master&lt;br /&gt;
    git am -3 ../moodle21/.patches/*                        (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) applies all the files from the .patches directory. When a patch does not apply cleanly, the command tries fall back on 3-way merge (see the -3 parameter). If conflicts occur during the procedure, you can either deal with them and then use `git am --continue` or abort the whole procedure with `git am --abort`.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
; Moodle forum discussions&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=168094 GIT help needed]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=165236 Best way to manage CONTRIB code with GIT]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167063 Handy Git tip for tracking 3rd-party modules and plugins]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167730 Moodle Git repositories]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=183409 Git help!! I don&#039;t understand rebase enough...]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=217617 add MOODLE_24_STABLE to github.com repository]&lt;br /&gt;
&lt;br /&gt;
; External resources &lt;br /&gt;
* [http://www.kernel.org/pub/software/scm/git/docs/everyday.html Everyday GIT With 20 Commands Or So]&lt;br /&gt;
* [http://gitref.org/ Git Reference]&lt;br /&gt;
* [http://progit.org/book/ Pro Git book]&lt;br /&gt;
* [http://vimeo.com/14629850 Getting git by Scott Chacon] - an recording of an excellent 1-hour presentation that introducing git, including a simple introduction to what is going on under the hood.&lt;br /&gt;
* [http://tjhunt.blogspot.co.uk/2012/03/fixing-bug-in-moodle-core-mechanics.html Tim Hunt&#039;s blog: Fixing a bug in Moodle core: the mechanics]&lt;br /&gt;
&lt;br /&gt;
[[Category:Git]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発者用Git]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=53128</id>
		<title>Git for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=53128"/>
		<updated>2017-10-24T07:25:16Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Specified the actual type of rebase required here. A first quick review to catch what describe in https://tracker.moodle.org/browse/MDL-57976?focusedCommentId=485633&amp;amp;page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-485633&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for helping you get started on Moodle development with Git. For further details of Git, see [[:Category:Git]].&lt;br /&gt;
&lt;br /&gt;
== General workflow ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A reasonable knowledge of the Git basics is a good idea before you start to use it for development. If you are new to Git, you are encouraged to go to &#039;See also&#039; for some more general reading.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:git-pushpull-model.png|right|thumb|400px|Moodle development workflow with Git]]&lt;br /&gt;
Detailed explanation of the workflow can be found in the [[Process]] page. In short, the Moodle development with Git looks like this:&lt;br /&gt;
&lt;br /&gt;
* You as the contributor commit changes into your personal repository at your computer&lt;br /&gt;
* You push the changes into your public repository and publish links to your changes in the Moodle Tracker&lt;br /&gt;
* You request a peer review of your code from another developer&lt;br /&gt;
* When peer reviewer is happy they submit issue for integration&lt;br /&gt;
* Moodle integrators pull the changes from your public repository and if they like them, they put them into Moodle integration repository&lt;br /&gt;
* The integrated change is tested and finally pushed into Moodle production repository&lt;br /&gt;
* You update your local repository with all changes from the production repository and the next cycle may start again&lt;br /&gt;
&lt;br /&gt;
This workflow runs in roughly weekly cycles. The integration happens on Monday and Tuesday and the testing on Wednesday. On Thursday (or Friday if testing takes too long), the production repository moodle.git is usually updated with changes from the last development week.&lt;br /&gt;
&lt;br /&gt;
Most Moodle developers have their public repositories hosted at [http://github.com/ Github]. Alternatively you may want to try [http://gitorious.org Gitorious] or the legendary [http://repo.or.cz repo.or.cz]. In the examples in this guide we assume you&#039;ll set up your public repository at Github.&lt;br /&gt;
&lt;br /&gt;
When you first register on tracker you can not assign issues to yourself or send them for peer review. You will be added to the developers group after your first bug fix is integrated. Before that just comment on the issue with a link to your branch and component lead or another developer will send issue for peer review for you.&lt;br /&gt;
&lt;br /&gt;
== Installing Git on your computer ==&lt;br /&gt;
&lt;br /&gt;
Install Git on your computer. Most Linux distributions have Git available as a package to install. On Debian/Ubuntu, type &#039;&#039;&#039;&#039;sudo apt-get install git&#039;&#039;&#039;&#039; on the terminal. If you are on Mac, [http://code.google.com/p/git-osx-installer/ git-osx-installer] installs it in a few clicks. &lt;br /&gt;
&lt;br /&gt;
Immediately after the installation, set your name and contact e-mail. The name and e-mail will become part of your commits and they can&#039;t be changed later once your commits are accepted into the Moodle code. Therefore we ask contributors to use their real names written in capital letters, eg &amp;quot;John Smith&amp;quot; and not &amp;quot;john smith&amp;quot; or even &amp;quot;john5677&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
    git config --global user.name &amp;quot;Your Name&amp;quot;&lt;br /&gt;
    git config --global user.email yourmail@domain.tld&lt;br /&gt;
&lt;br /&gt;
Unless you are the repository maintainer, it is wise to set your Git to not push changes in file permissions:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.filemode false&lt;br /&gt;
&lt;br /&gt;
Also, it&#039;s recommended to verify that the your git installation is not performing any transformation between LFs and CRLFs. All Moodle &#039;&#039;&#039;uses only LFs&#039;&#039;&#039; and you should &#039;&#039;&#039;fetch/edit and push&#039;&#039;&#039; it that way (may need to configure your editor/IDE too). Note that having any &amp;quot;magic&amp;quot; enabled is known to cause [[Common unit test problems#The_test_file_.22evolution.test.22_should_not_contain_section_named_.22.5Blots_of_content.5D.22|problems with unit tests]] execution. So we recommend you to set:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.autocrlf false&lt;br /&gt;
&lt;br /&gt;
== Setting-up the public repository ==&lt;br /&gt;
&lt;br /&gt;
1. Go to [http://github.com/ Github] and create an account.&lt;br /&gt;
&lt;br /&gt;
2. Go to the [http://github.com/moodle/moodle official Moodle Github repository] and click on the Fork button. You now have your own Github Moodle repository.&lt;br /&gt;
&lt;br /&gt;
3. Now you need to set up your SSH public key, so you can push to your Github Moodle repository from your local Moodle repository. On Mac you can go on this [http://help.github.com/mac-key-setup/ Github help page]. If you are on another system, go to your Github administration page, to the section SSH Public Keys, and you should see a link to a help page. Done? Good! That was the most difficult part!&lt;br /&gt;
&lt;br /&gt;
== Setting-up the local repository at your computer  ==&lt;br /&gt;
&lt;br /&gt;
Create a local clone repository of your Github repository. In a terminal:&lt;br /&gt;
&lt;br /&gt;
    git clone git://github.com/YOUR_GITHUB_USERNAME/moodle.git LOCALDIR&lt;br /&gt;
&lt;br /&gt;
    (or:  git clone git@github.com:YOUR_GITHUB_USERNAME/moodle.git LOCALDIR)&lt;br /&gt;
&lt;br /&gt;
This command does several jobs for you. It creates a new folder, initializes an empty Git repository in it, sets your Github repository as the remote repository called &#039;origin&#039; and makes a local checkout of the branch &#039;master&#039; from it. The important point to remember now is that your Github repository is aliased as &#039;origin&#039; for your local clone.&lt;br /&gt;
&lt;br /&gt;
Note that the format of the URL here is important. In the first example, the URL starts &amp;quot;git://github.com&amp;quot; and this will give read-only access to the repository at github.com. If you use this URL, the &amp;quot;git push origin&amp;quot; command that appears later in this document will not work. Therefore, if you want to be able to update the &amp;quot;origin&amp;quot; repository, you should use the URL that starts &amp;quot;git@github.com&amp;quot;, i.e. the second of the two &amp;quot;git clone&amp;quot; commands given above. This will give you read and write access to the repository on github.com.&lt;br /&gt;
&lt;br /&gt;
== Keeping your public repository up-to-date ==&lt;br /&gt;
&lt;br /&gt;
[[image:git-sync-github.png|right|thumb|400px|Fetching changes from upstream and pushing them to github]]&lt;br /&gt;
Your fork at Github is not updated automatically. To keep it synced with the upstream Moodle repository, you have to fetch the recent changes from the official moodle.git and push them to your public repository. To avoid problems with this it is strongly recommended that you never modify the standard Moodle branches. &#039;&#039;Remember: never commit directly into master and MOODLE_xx_STABLE branches.&#039;&#039; In other words, always create topic branches to work on. In Gitspeak, the master branch and MOODLE_xx_STABLE branches should be always fast-forwardable.&lt;br /&gt;
&lt;br /&gt;
To keep your public repository up-to-date, we will register remote repository git://git.moodle.org/moodle.git under &#039;upstream&#039; alias. Then we create a script to be run regularly that fetches changes from the upstream repository and pushes them to your public repository. Note that this procedure will not affect your local working directory.&lt;br /&gt;
&lt;br /&gt;
To register the upstream remote:&lt;br /&gt;
&lt;br /&gt;
    cd moodle&lt;br /&gt;
    git remote add upstream git://git.moodle.org/moodle.git&lt;br /&gt;
&lt;br /&gt;
The following commands can be used to keep the standard Moodle branches at your Github repository synced with the upstream repository. You may wish to store them in a script so that you can run it every week after the upstream repository is updated.&lt;br /&gt;
&lt;br /&gt;
    #!/bin/bash&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    for BRANCH in MOODLE_{19..33}_STABLE master; do&lt;br /&gt;
        git push origin refs/remotes/upstream/$BRANCH:refs/heads/$BRANCH&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
The git-fetch command does not modify your current working dir (your checkout). It just downloads all recent changes from a remote repository and stores them into so called remote-tracking branches. The git-push command takes these remote-tracking branches from upstream and pushes them to Github under the same name. Understanding this fully requires a bit knowledge of Git internals - see gitrevisions(7) man page.&lt;br /&gt;
&lt;br /&gt;
Note there is no need to switch the local branch during this. You can even execute this via cron at your machine. Just note that the upstream repository updates typically just once a week.&lt;br /&gt;
&lt;br /&gt;
=== New branches ===&lt;br /&gt;
&lt;br /&gt;
Occasionally, moodle.org will create a new branch that does not exist in your public (e.g. Github.com) repository. If you try to push this new branch, you will see an error such as the following:&lt;br /&gt;
&lt;br /&gt;
    error: unable to push to unqualified destination: MOODLE_99_STABLE&lt;br /&gt;
    The destination refspec neither matches an existing ref on the remote&lt;br /&gt;
    nor begins with refs/, and we are unable to guess a prefix based on the source ref.&lt;br /&gt;
    error: failed to push some refs to &#039;git@github.com:YOUR_GITHUB_USERNAME/moodle.git&#039;&lt;br /&gt;
&lt;br /&gt;
In the above example, &amp;quot;MOODLE_99_STABLE&amp;quot;, is the name of the new branch that does not exist in your public repository. To fix the error, you need to create the new branch on your public repository, using the following commands, replacing &amp;quot;MOODLE_99_STABLE&amp;quot; with the name of the new branch you wish to create:&lt;br /&gt;
&lt;br /&gt;
    git checkout MOODLE_99_STABLE&lt;br /&gt;
    git push origin MOODLE_99_STABLE:MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
The above code will create a new copy of the &amp;quot;MOODLE_99_STABLE&amp;quot; branch in your local repository. If you do not need to keep a local copy of the new branch - and probably you do not need it, you then can remove it from your local repository as follows:&lt;br /&gt;
&lt;br /&gt;
    git checkout master&lt;br /&gt;
    git branch -D MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
== Preparing a patch ==&lt;br /&gt;
&lt;br /&gt;
As said earlier at this page, you never work on standard Moodle branches directly. Every time you are going to edit something, switch to a local branch. Fork the local branch off the standard branch you think it should be merged to. So if you are working on a patch for 1.9 or 2.0, fork the branch off MOODLE_19_STABLE or MOODLE_20_STABLE, respectively. Patches for the next [[Moodle versions|major version]] should be based on the master branch.&lt;br /&gt;
&lt;br /&gt;
    git checkout -b MDL-xxxxx-nasty-bug origin/master&lt;br /&gt;
&lt;br /&gt;
Note that if you forget to specify the starting point, the branch is based on the currently checked-out branch. It may not be what you want. It is recommended to always specify the starting point.&lt;br /&gt;
&lt;br /&gt;
To check the current branch, run&lt;br /&gt;
&lt;br /&gt;
    git branch&lt;br /&gt;
&lt;br /&gt;
The current branch is highlighted.&lt;br /&gt;
&lt;br /&gt;
Now go and fix the issue with your favorite IDE. Check the status of the files, view the change to be committed and finally commit the change:&lt;br /&gt;
&lt;br /&gt;
    vim filename.php&lt;br /&gt;
    git status&lt;br /&gt;
    git diff&lt;br /&gt;
    git commit -a&lt;br /&gt;
&lt;br /&gt;
Note that this is safe as the commit is recorded just locally, nothing is sent to any server yet (as it would in CVS). To see history of the commits, use&lt;br /&gt;
&lt;br /&gt;
    git log&lt;br /&gt;
&lt;br /&gt;
Once your local branch contains the change (note that it may consists of several patches) and you are happy with it, publish the branch at your public repository:&lt;br /&gt;
&lt;br /&gt;
    git push origin MDL-xxxxx-nasty-bug&lt;br /&gt;
&lt;br /&gt;
Now as your branch is published, you can ask Moodle core developers to review it and eventually integrate it into the standard Moodle repository.&lt;br /&gt;
&lt;br /&gt;
=== Changing commit message, reordering and squashing commits ===&lt;br /&gt;
&lt;br /&gt;
It often happens that you made a mistake in your patch or in the commit message and helpful CiBot pointed it out for you. You can &amp;quot;rewrite the history&amp;quot; and change the existing commits.&lt;br /&gt;
&lt;br /&gt;
Option 1. Reset all the changes in the branch and commit again. &lt;br /&gt;
&lt;br /&gt;
    git reset --mixed origin/master&lt;br /&gt;
&lt;br /&gt;
Now all your changes are still present but all commits on top of &amp;quot;master&amp;quot; branch are gone. You can create a new commit&lt;br /&gt;
&lt;br /&gt;
Option 2. Discover &#039;&#039;&#039;git rebase --interactive&#039;&#039;&#039; - this is a powerful tool to change the sequence of commit, change the commit messages, squash commits, etc. We will not cover it here, there are many articles in the Internet about it.&lt;br /&gt;
&lt;br /&gt;
Whatever option you chose, you have &amp;quot;rewritten the history&amp;quot; and you can not simply push the changes to github again because they would need to overwrite the commits that were already pushed. If you try &amp;quot;git push MDL-xxxxx-nasty-bug&amp;quot; you will get an error message suggesting you to force push. &lt;br /&gt;
To force push the changed commits use:&lt;br /&gt;
&lt;br /&gt;
    git push -f origin MDL-xxxxx-nasty-bug&lt;br /&gt;
&lt;br /&gt;
If an error occurs because you are still using the git protocol (read only), use this command : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin https://github.com/&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
A prompt will ask for your credentials, if you previously setup your SSH public key you can also use this one : &lt;br /&gt;
&lt;br /&gt;
    git remote set-url origin git@github.com:&amp;lt;user.name&amp;gt;/moodle.git&lt;br /&gt;
&lt;br /&gt;
=== Checking if a branch has already been merged ===&lt;br /&gt;
&lt;br /&gt;
After some time contributing to Moodle you would have a lot of branches both in your local repository and in your public repository. To prune their list and delete those that were accepted by upstream, use the following&lt;br /&gt;
&lt;br /&gt;
    git fetch upstream                                      (1)&lt;br /&gt;
    git branch --merged upstream/master                     (2)&lt;br /&gt;
    git branch --merged upstream/MOODLE_20_STABLE           (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) fetches the changes from your upstream repository at git.moodle.org (remember that git-fetch does not modify your working dir so it is safe to run it whenever). Command (2) and (3) print all branches that are merged into the upstream master branch and MOODLE_20_STABLE branch, respectively. To delete these local branches, use&lt;br /&gt;
&lt;br /&gt;
    git branch -d MDL-xxxxx-accepted-branch&lt;br /&gt;
&lt;br /&gt;
The similar approach can be used to check the branches published at your origin repository at github.com&lt;br /&gt;
&lt;br /&gt;
    git fetch origin                                        (1)&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    git branch -r --merged upstream/master                  (2)&lt;br /&gt;
    git branch -r --merged upstream/MOODLE_20_STABLE        (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) makes sure that you have all your branches from github.com recorded as the remote tracking branch locally. Commands (2) and (3) work the same as in the previous example but they list remote tracking branches only ([http://www.kernel.org/pub/software/scm/git/docs/git-branch.html see -r param]). To delete a branch at github.com, use&lt;br /&gt;
&lt;br /&gt;
    git push origin :MDL-xxxx-branch-to-delete&lt;br /&gt;
&lt;br /&gt;
This syntax may look weird to you. However it is pretty logical. The general syntax of the git-push command is&lt;br /&gt;
&lt;br /&gt;
    git push &amp;lt;repository&amp;gt; &amp;lt;source ref&amp;gt;:&amp;lt;target ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so deleting a remote branch can be understood as pushing an &amp;quot;empty (null) reference&amp;quot; to it.&lt;br /&gt;
&lt;br /&gt;
== Peer-reviewing someone else&#039;s code ==&lt;br /&gt;
&lt;br /&gt;
To review a branch that someone else pushed into their public repository, you do not need to register a new remote (unless you work with such repository frequently, of course). Let us imagine your friend Alice pushed a work-in-progress branch called &#039;wip-feature&#039; into her Github repository and asked you to review it. You need to know the read-only address of the repository and the name of the branch.&lt;br /&gt;
&lt;br /&gt;
    git fetch git://github.com/alice/moodle.git wip-feature&lt;br /&gt;
&lt;br /&gt;
This will download all required data and will keep the pointer to the tip of the wip-feature branch in a local symbolic reference FETCH_HEAD. To see what&#039;s there on that branch, use&lt;br /&gt;
&lt;br /&gt;
    git log -p FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see how a particular file looks at Alice&#039;s branch&lt;br /&gt;
&lt;br /&gt;
    git show FETCH_HEAD:admin/blocks.php&lt;br /&gt;
&lt;br /&gt;
To create a new local branch called &#039;alice-wip-feature&#039; containing the work by Alice, use&lt;br /&gt;
&lt;br /&gt;
    git checkout -b alice-wip-feature FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To merge Alice&#039;s work into your current branch:&lt;br /&gt;
&lt;br /&gt;
    git merge FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see what would be merged into the current branch without actually modifying anything:&lt;br /&gt;
&lt;br /&gt;
    git diff ...FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
Once you are all set and reviewing code, this [[Peer_reviewing_checklist|checklist]] should prove to be useful.&lt;br /&gt;
&lt;br /&gt;
== Rebasing a branch ==&lt;br /&gt;
&lt;br /&gt;
Rebasing is a process when you cut off the branch from its current start point and transplant it to another point. Let us assume the following history exists:&lt;br /&gt;
&lt;br /&gt;
          A---B---C topic&lt;br /&gt;
         /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
From this point, the result of the command:&lt;br /&gt;
&lt;br /&gt;
    git rebase master topic&lt;br /&gt;
&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
                  A&#039;--B&#039;--C&#039; topic&lt;br /&gt;
                 /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
and would end with &#039;topic&#039; being your current branch.&lt;br /&gt;
&lt;br /&gt;
You may be asked to rebase your branch submitted for the integration if the submitted branch was based on an outdated commit. The typical case is if you create a new branch as a fork off the upstream master branch on Tuesday. Then on Wednesday, the upstream master branch grows as all changes from the last integration cycle are merged to it. To make diff easy on Github for next weekly pull request review, you want to rebase your branch against the updated master.&lt;br /&gt;
&lt;br /&gt;
    git rebase master MDL-xxxxx-topic-branch&lt;br /&gt;
&lt;br /&gt;
Note that rebasing effectively rewrites the history of the branch. &#039;&#039;&#039;Do not rebase the branch if there is a chance that somebody has already forked it and based their own branch on it.&#039;&#039;&#039; For this reason, many Git tutorials discourage from rebasing any branch that has been published. However in Moodle, all branches submitted for integration are potential subject of rebase (even though we try to not to do it often) and you should not base your own branches on them.&lt;br /&gt;
&lt;br /&gt;
=== Conflicts during rebase ===&lt;br /&gt;
&lt;br /&gt;
During the rebase procedure, conflicts may appear. git-status commands reports the conflicted files. Explore them carefully and fix them in your editor (like you would do with CVS). Then add the files with &#039;git add&#039; command and continue.&lt;br /&gt;
&lt;br /&gt;
    vim conflicted.php&lt;br /&gt;
    git add conflicted.php&lt;br /&gt;
    git rebase --continue&lt;br /&gt;
&lt;br /&gt;
== Applying changes from one branch to another ==&lt;br /&gt;
&lt;br /&gt;
Most bugs are fixed at a stable branch (like MOODLE_20_STABLE) and the fix must be prepared for other branches, too (like MOODLE_21_STABLE and the main development branch - master). In Moodle, we do not merge stable branches into the master one. So usually the contributor prepares at least two branches - with the fix for the stable branch(es) and with the fix for the master branch.&lt;br /&gt;
&lt;br /&gt;
If you have a patch prepared on a local branch (let us say MDL-xxxx-topic_20_STABLE), it is possible to re-apply it to another branch.&lt;br /&gt;
&lt;br /&gt;
=== Cherry-picking a single commit ===&lt;br /&gt;
&lt;br /&gt;
Let us have two local Git repositories ~/public_html/moodle21 containing local installation of Moodle 2.1 and ~/public_html/moodledev with the local installation of most recent development version of Moodle. They both use your public repository at github.com as the origin. You have a branch in moodle21 called MDL-xxxx-topic_21_STABLE that was forked off MOODLE_21_STABLE. It contains one commit. Now you want to re-apply this commit to a branch MDL-xxxx-topic in moodledev.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master            (1)&lt;br /&gt;
    git fetch ../moodle21 MDL-xxxx-topic_21_STABLE          (2)&lt;br /&gt;
    git cherry-pick FETCH_HEAD                              (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) creates new local branch forked off the master. The command (2) fetches all data needed to re-apply the topic branch and stores the pointer to the tip of that branch to FETCH_HEAD symbolic reference. The command (3) picks the tip of the branch (the top-most commit on it) and tries to apply it on the current branch.&lt;br /&gt;
There is also a variant of the cherry-pick command that supports multiple commits, shortly (see its man page for details): &amp;lt;code bash&amp;gt;$ git cherry-pick A^..B&amp;lt;/code&amp;gt; if you want to include from A - see &#039;&#039;&#039;^&#039;&#039;&#039; - to B, A should be older than B. We will use another approach for cherry-picking multiple commits.&lt;br /&gt;
&lt;br /&gt;
=== Applying a set of patches ===&lt;br /&gt;
&lt;br /&gt;
If the branch MDL-xxxx-topic_21_STABLE from the previous example consists of several commits, it may be easier to use git-format-patch and git-am combo to re-apply the whole set of patches (aka patchset). Firstly you will export all commits from the topic branch to files.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodle21&lt;br /&gt;
    mkdir .patches&lt;br /&gt;
    git format-patch -o .patches MOODLE_21_STABLE..MDL-xxxx-topic_21_STABLE         (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) takes all commits from the topic branch that are not in MOODLE_21_STABLE and exports them one by one to the output directory .patches. Look at the generated files. They contain the patch itself (in diff format) and additional information about the commit. You could eg send these files by email to a friend of yours for peer-review. We will use them in another repository.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master&lt;br /&gt;
    git am -3 ../moodle21/.patches/*                        (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) applies all the files from the .patches directory. When a patch does not apply cleanly, the command tries fall back on 3-way merge (see the -3 parameter). If conflicts occur during the procedure, you can either deal with them and then use `git am --continue` or abort the whole procedure with `git am --abort`.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
; Moodle forum discussions&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=168094 GIT help needed]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=165236 Best way to manage CONTRIB code with GIT]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167063 Handy Git tip for tracking 3rd-party modules and plugins]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167730 Moodle Git repositories]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=183409 Git help!! I don&#039;t understand rebase enough...]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=217617 add MOODLE_24_STABLE to github.com repository]&lt;br /&gt;
&lt;br /&gt;
; External resources &lt;br /&gt;
* [http://www.kernel.org/pub/software/scm/git/docs/everyday.html Everyday GIT With 20 Commands Or So]&lt;br /&gt;
* [http://gitref.org/ Git Reference]&lt;br /&gt;
* [http://progit.org/book/ Pro Git book]&lt;br /&gt;
* [http://vimeo.com/14629850 Getting git by Scott Chacon] - an recording of an excellent 1-hour presentation that introducing git, including a simple introduction to what is going on under the hood.&lt;br /&gt;
* [http://tjhunt.blogspot.co.uk/2012/03/fixing-bug-in-moodle-core-mechanics.html Tim Hunt&#039;s blog: Fixing a bug in Moodle core: the mechanics]&lt;br /&gt;
&lt;br /&gt;
[[Category:Git]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発者用Git]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Automatic_class_loading&amp;diff=52526</id>
		<title>Automatic class loading</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Automatic_class_loading&amp;diff=52526"/>
		<updated>2017-05-25T20:36:39Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Fixed typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.6}}&lt;br /&gt;
&lt;br /&gt;
This document describes how to use the functionality of the automatic classloader provided by Moodle.&lt;br /&gt;
&lt;br /&gt;
==Class naming==&lt;br /&gt;
&lt;br /&gt;
To be discoverable by the Moodle automatic classloader, classes must adhere to the following class naming rules:&lt;br /&gt;
* [[Frankenstyle]] Prefixes&lt;br /&gt;
** Core classes must start with the prefix &#039;&#039;core_&#039;&#039;.&lt;br /&gt;
** Plugin class names must start with names such as &#039;&#039;plugintype_pluginname_&#039;&#039;. For example: &#039;&#039;mod_forum_&#039;&#039; (in the example of /mod/forum)&lt;br /&gt;
* One class file for each class&lt;br /&gt;
* Class file names must be class name without Frankenstyle prefix&lt;br /&gt;
** e.g. Class &#039;&#039;&#039;mod_forum_some_class&#039;&#039;&#039; is stored in file &#039;&#039;&#039;mod/forum/classes/some_class.php&#039;&#039;&#039;&lt;br /&gt;
** e.g. Class &#039;&#039;&#039;core_frankenstyle&#039;&#039;&#039; class is stored in &#039;&#039;&#039;lib/classes/frankenstyle.php&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==Class files and locations==&lt;br /&gt;
&lt;br /&gt;
The Moodle automatic classloader looks for classes only in specific locations (all caps represents a symbolic name, replace it with a real location)&lt;br /&gt;
* Core classes&lt;br /&gt;
** &#039;&#039;&#039;/lib/classes/&#039;&#039;&#039; and its subdirectories&lt;br /&gt;
** &#039;&#039;&#039;SUBSYSTEMDIR/classes/&#039;&#039;&#039; and its subdirectories&lt;br /&gt;
*** The list of subsystems and their respective directories can be found in code (/lib/classes/component.php, function fetch_subsystems)&lt;br /&gt;
* Plugin classes&lt;br /&gt;
** /PLUGIN/DIR/classes and its subdirectories&lt;br /&gt;
&lt;br /&gt;
==Code Examples==&lt;br /&gt;
&lt;br /&gt;
Example of autoloaded class in forum module:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file mod/forum/classes/some_class.php&lt;br /&gt;
&lt;br /&gt;
class mod_forum_some_class {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file mod/forum/lib.php&lt;br /&gt;
&lt;br /&gt;
// no require_once() necessary here&lt;br /&gt;
&lt;br /&gt;
$instance = new mod_forum_some_class();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// in any file&lt;br /&gt;
&lt;br /&gt;
if (class_exists(&#039;mod_forum_some_class&#039;)) {&lt;br /&gt;
  // do something&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Namespaces==&lt;br /&gt;
&lt;br /&gt;
PHP namespaces are designed to improve code organisation in your projects. Directory structure in classes/ is matching the namespace structure.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace core\event;&lt;br /&gt;
&lt;br /&gt;
// file lib/classes/event/base.php&lt;br /&gt;
&lt;br /&gt;
class base {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
namespace mod_forum\event;&lt;br /&gt;
&lt;br /&gt;
// file mod/forum/classes/event/post_read.php&lt;br /&gt;
&lt;br /&gt;
class post_read extends \core\event\base {&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
// in any file&lt;br /&gt;
&lt;br /&gt;
\mod_forum\event\post_read::create($post-&amp;gt;id, ...)-&amp;gt;trigger();&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note there are restrictions on valid choices for the first and second level namespaces in Moodle - see [[Coding_style#Namespaces]] for more info.&lt;br /&gt;
&lt;br /&gt;
==Backwards compatibility==&lt;br /&gt;
There are no know issues that could cause backwards incompatibility, however it is strongly recommended to use the classes subdirectory only for classes that are included automatically.&lt;br /&gt;
&lt;br /&gt;
==Performance and developer mode==&lt;br /&gt;
&lt;br /&gt;
Class autoloading improves performance and reduces memory footprint. Location of all classes is automatically stored in class map cache, the cache is updated automatically before upgrade or installation, during cache reset and in developer mode.&lt;br /&gt;
&lt;br /&gt;
There is only one inconvenience - if you add new class or remove it you need to do one of the following:&lt;br /&gt;
* visit yourserver/admin/index.php&lt;br /&gt;
* purge caches&lt;br /&gt;
* or add &#039;&#039;&#039;$CFG-&amp;gt;debug = (E_ALL | E_STRICT);&#039;&#039;&#039; to your config.php&lt;br /&gt;
&lt;br /&gt;
Otherwise the new class would not be found.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Frankenstyle]]&lt;br /&gt;
* [[Automatic Class Loading Proposal]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Global_search&amp;diff=49595</id>
		<title>Global search</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Global_search&amp;diff=49595"/>
		<updated>2016-03-04T22:01:08Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: /* Linux */ This section is actually for a Debian/Ubuntu based Linux distro.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Installation =&lt;br /&gt;
&lt;br /&gt;
To use Solr as Moodle&#039;s search engine you need the PHP Solr extension and a Solr server.&lt;br /&gt;
&lt;br /&gt;
== PHP Solr extension ==&lt;br /&gt;
&lt;br /&gt;
You need PHP Solr extension installed. Use PECL Solr Extension 1.x for Solr Server 3.x, or use PECL Solr 2.x for Solr Server 4.0+.&lt;br /&gt;
&lt;br /&gt;
You can download the official latest versions from [http://pecl.php.net/package/solr](http://pecl.php.net/package/solr)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Basic installation steps (using apache web server):&lt;br /&gt;
&lt;br /&gt;
=== Linux (Debian/Ubuntu) ===&lt;br /&gt;
&lt;br /&gt;
    sudo apt-get install libpcre3-dev libxml2-dev libcurl4-openssl-dev&lt;br /&gt;
    sudo pecl install solr&lt;br /&gt;
    sudo service apache2 restart&lt;br /&gt;
    sudo sh -c &amp;quot;echo &#039;extension=solr.so&#039; &amp;gt; /etc/php5/apache2/conf.d/solr.ini&amp;quot;&lt;br /&gt;
    sudo sh -c &amp;quot;echo &#039;extension=solr.so&#039; &amp;gt; /etc/php5/cli/conf.d/solr.ini&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== OSX using macports ===&lt;br /&gt;
&lt;br /&gt;
    sudo port install apache-solr4&lt;br /&gt;
    sudo port install php54-solr&lt;br /&gt;
&lt;br /&gt;
=== Windows ===&lt;br /&gt;
&lt;br /&gt;
Install the pecl package as usual. Sorry it has not been tested yet.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Solr server ==&lt;br /&gt;
&lt;br /&gt;
The following snippet (feel free to copy &amp;amp; paste into a .sh script with execution permissions) will download Solr 5.4.1 in the current directory, start the solr server and create an index in it named &#039;&#039;&#039;moodle&#039;&#039;&#039; to add moodle data to it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
    #!/bin/bash&lt;br /&gt;
    set -e&lt;br /&gt;
    SOLRVERSION=5.4.1&lt;br /&gt;
    SOLRNAME=solr-$SOLRVERSION&lt;br /&gt;
    SOLRTAR=$SOLRNAME&#039;.tgz&#039;&lt;br /&gt;
    INDEXNAME=moodle&lt;br /&gt;
    if [ -d $SOLRNAME ]; then&lt;br /&gt;
        echo &amp;quot;Error: Directory $SOLRNAME already exists, remove it before starting the setup again.&amp;quot;&lt;br /&gt;
        exit 1&lt;br /&gt;
    fi&lt;br /&gt;
    if [ ! -f $SOLRTAR ]; then&lt;br /&gt;
        wget http://apache.mirror.digitalpacific.com.au/lucene/solr/$SOLRVERSION/$SOLRTAR&lt;br /&gt;
    fi&lt;br /&gt;
    tar -xvzf $SOLRTAR&lt;br /&gt;
    cd $SOLRNAME&lt;br /&gt;
    bin/solr start&lt;br /&gt;
    bin/solr create -c $INDEXNAME&lt;br /&gt;
    # After setting it up and creating the index use:&lt;br /&gt;
    # - &amp;quot;/yourdirectory/solrdir/bin/solr start&amp;quot; from CLI to start the server&lt;br /&gt;
    # - &amp;quot;/yourdirectory/solrdir/bin/solr stop&amp;quot; from CLI to stop the server.&lt;br /&gt;
&lt;br /&gt;
= Setup =&lt;br /&gt;
&lt;br /&gt;
# Go to &#039;&#039;&#039;Site administration -&amp;gt; Plugins -&amp;gt; Search -&amp;gt; Manage global search&#039;&#039;&#039;&lt;br /&gt;
# Follow &#039;&#039;&#039;Search setup&#039;&#039;&#039; steps to complete the setup process. Basically you have to:&lt;br /&gt;
## Enable global search&lt;br /&gt;
## Set &#039;&#039;&#039;Solr&#039;&#039;&#039; as search engine and tick all search areas checkboxes&lt;br /&gt;
## Go to &#039;&#039;&#039;Site administration -&amp;gt; Plugins -&amp;gt; Search -&amp;gt; Solr&#039;&#039;&#039; and set &#039;&#039;&#039;Host name&#039;&#039;&#039; to localhost, &#039;&#039;&#039;Port&#039;&#039;&#039; to 8983 and &#039;&#039;&#039;Index name&#039;&#039;&#039; to &#039;moodle&#039; (the name of the index in Solr)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Indexing =&lt;br /&gt;
&lt;br /&gt;
Once global search is enabled a new task will be running through cron, although you can force documents indexing by:&lt;br /&gt;
&lt;br /&gt;
# Going to &#039;&#039;&#039;Reports -&amp;gt; Global search info&#039;&#039;&#039;&lt;br /&gt;
# Tick &#039;&#039;&#039;Index all site contents&#039;&#039;&#039; and press &#039;&#039;&#039;Execute&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
* Executing the following task from CLI&lt;br /&gt;
&lt;br /&gt;
    php admin/tool/task/cli/schedule_task.php --execute=&amp;quot;\\core\\task\\search_task&amp;quot;&lt;br /&gt;
&lt;br /&gt;
= Querying =&lt;br /&gt;
&lt;br /&gt;
# Hover the search icon in the navigation bar, type your query and press &#039;&#039;&#039;Enter&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
or&lt;br /&gt;
&lt;br /&gt;
# Add &#039;&#039;&#039;Global search&#039;&#039;&#039; block somewhere&lt;br /&gt;
# Type your query and press &#039;&#039;&#039;Search&#039;&#039;&#039;&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=49194</id>
		<title>Blocks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=49194"/>
		<updated>2016-01-05T17:32:06Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Removed the just added mention to the &amp;quot;NEWMODULE&amp;quot; docs to prevent confusing newbies. Thanks to David Mudrák for the support!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039; A Step-by-step Guide To Creating Blocks &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Original Author: Jon Papaioannou ([mailto:pj@moodle.org pj@moodle.org])&lt;br /&gt;
&lt;br /&gt;
Updated to Moodle 2.0 and above by: Greg J Preece ([mailto:greg.preece@blackboard.com greg.preece@blackboard.com])&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
The present document serves as a guide to developers who want to create their own blocks for use in Moodle. It applies to the 2.0 development version of Moodle (and any newer) &#039;&#039;&#039;only&#039;&#039;&#039;, as the blocks API changed significantly enough to warrant new documentation. Those wishing to read the old tutorial for Moodles 1.5 to 1.9 can find it under [[Blocks/Blocks for 1.5 to 1.9| Blocks for 1.5 to 1.9]].&lt;br /&gt;
&lt;br /&gt;
The guide is written as an interactive course which aims to develop a configurable, multi-purpose block that displays arbitrary HTML. It&#039;s targeted mainly at people with little experience with Moodle or programming in general and aims to show how easy it is to create new blocks for Moodle. A certain small amount of PHP programming knowledge is still required, though. &lt;br /&gt;
&lt;br /&gt;
Experienced developers and those who just want a &#039;&#039;&#039;programmer&#039;s reference&#039;&#039;&#039; text should refer to [[Blocks/Appendix_A| Appendix A]] because the main guide has a rather low concentration of pure information in the text.&lt;br /&gt;
&lt;br /&gt;
== Basic Concepts ==&lt;br /&gt;
&lt;br /&gt;
Through this guide, we will be following the creation of an &amp;quot;HTML&amp;quot; block from scratch in order to demonstrate most of the block features at our disposal. Our block will be named &amp;quot;SimpleHTML&amp;quot;. This does not constrain us regarding the name of the actual directory on the server where the files for our block will be stored, but for consistency we will follow the practice of using the lowercased form &amp;quot;simplehtml&amp;quot; in any case where such a name is required. &lt;br /&gt;
&lt;br /&gt;
Whenever we refer to a file or directory name which contains &amp;quot;simplehtml&amp;quot;, it&#039;s important to remember that &#039;&#039;only&#039;&#039; the &amp;quot;simplehtml&amp;quot; part is up to us to change; the rest is standardised and essential for Moodle to work correctly.&lt;br /&gt;
&lt;br /&gt;
Whenever a file&#039;s path is mentioned in this guide, it will always start with a slash. This refers to the Moodle home directory; all files and directories will be referred to with respect to that directory.&lt;br /&gt;
&lt;br /&gt;
== Ready, Set, Go! ==&lt;br /&gt;
&lt;br /&gt;
To define a &amp;quot;block&amp;quot; in Moodle, in the most basic case we need to provide just four PHP files. Remember, in this example we are creating a block called &#039;simplehtml&#039;, replace &#039;simplehtml&#039; with the name of your custom block. The four files should be located in blocks/simplehtml and are:&lt;br /&gt;
&lt;br /&gt;
=== block_simplehtml.php ===&lt;br /&gt;
&lt;br /&gt;
This file will hold the class definition for the block, and is used both to manage it as a plugin and to render it onscreen.&lt;br /&gt;
&lt;br /&gt;
We start by creating the main object file, &#039;block_simplehtml.php&#039;. We then begin coding the block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
class block_simplehtml extends block_base {&lt;br /&gt;
    public function init() {&lt;br /&gt;
        $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // The PHP tag and the curly bracket for the class definition &lt;br /&gt;
    // will only be closed after there is another function added in the next section.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line is our block class definition; it must be named exactly in the manner shown. Again, only the &amp;quot;simplehtml&amp;quot; part can (and indeed must) change; everything else is standardised.&lt;br /&gt;
&lt;br /&gt;
Our class is then given a small method: [[Blocks/Appendix_A#init.28.29| init()]]. This is essential for all blocks, and its purpose is to give values to any class member variables that need instantiating. &lt;br /&gt;
&lt;br /&gt;
In this very basic example, we only want to set [[Blocks/Appendix_A#.24this-.3Etitle| $this-&amp;gt;title]], which is the title displayed in the header of our block. We can set it to whatever we like; in this case it&#039;s set to read the actual title from the language file mentioned below, which is then distributed along with the block. I&#039;ll skip ahead a bit here and say that if you want your block to display &#039;&#039;&#039;no&#039;&#039;&#039; title at all, then you should set this to any descriptive value you want (but &#039;&#039;&#039;not&#039;&#039;&#039; make it an empty string). We will later see [[Blocks#Eye_Candy|how to disable the title&#039;s display]].&lt;br /&gt;
&lt;br /&gt;
=== db/access.php ===&lt;br /&gt;
&lt;br /&gt;
This file will hold the new capabilities created by the block.&lt;br /&gt;
&lt;br /&gt;
Moodle 2.4 onwards introduced the capabilities addinstance and myaddinstance for core blocks. They were introduced so that it was possible to control the use of individual blocks. These capabilities should also be added to your custom block, so in this case to the file blocks/simplehtml/db/access.php. If your block is not going to be used in the &#039;My Moodle page&#039; (ie, your applicable_formats function (discussed later) has &#039;my&#039; set to false.) then the myaddinstance capability is not required. The following is the capabilities array and how it should look for any new blocks.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
    $capabilities = array(&lt;br /&gt;
&lt;br /&gt;
    &#039;block/simplehtml:myaddinstance&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_SYSTEM,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;user&#039; =&amp;gt; CAP_ALLOW&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
        &#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/my:manageblocks&#039;&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    &#039;block/simplehtml:addinstance&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039; =&amp;gt; RISK_SPAM | RISK_XSS,&lt;br /&gt;
&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_BLOCK,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;editingteacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;manager&#039; =&amp;gt; CAP_ALLOW&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
        &#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/site:manageblocks&#039;&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== lang/en/block_simplehtml.php ===&lt;br /&gt;
&lt;br /&gt;
This is the English language file for your block. If you are not an English speaker, you can replace &#039;en&#039; with your appropriate language code. All language files for blocks go under the /lang subfolder of the block&#039;s installation folder.&lt;br /&gt;
&lt;br /&gt;
Moodle 2.0 and above require a name for our plugin to show in the upgrading page. We set this value, along with the capabilities we created and any other language strings we wish to use within the block, in a language package as previously mentioned (the same file where we put our string for the plugin title).&lt;br /&gt;
&lt;br /&gt;
The capabilities added above need descriptions for pages that allow setting of capabilities. These should also be added to the language file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Simple HTML block&#039;;&lt;br /&gt;
$string[&#039;simplehtml&#039;] = &#039;Simple HTML&#039;;&lt;br /&gt;
$string[&#039;simplehtml:addinstance&#039;] = &#039;Add a new simple HTML block&#039;;&lt;br /&gt;
$string[&#039;simplehtml:myaddinstance&#039;] = &#039;Add a new simple HTML block to the My Moodle page&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== version.php ===&lt;br /&gt;
&lt;br /&gt;
This file will hold version information for the plugin, along &#039;&#039;&#039;with other advanced parameters&#039;&#039;&#039; (not covered here - see [[version.php]] if you want &#039;&#039;&#039;more details&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Prior to Moodle 2.0, version details for blocks were stored as class fields; as of Moodle 2.0 these are stored in a file called version.php, stored under &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;version.php&#039;&#039;&#039;&#039;&#039;. The version file is very simple indeed, containing only a few field definitions, depending on your needs. Here is an example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$plugin-&amp;gt;component = &#039;block_simplehtml&#039;;  // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494)&lt;br /&gt;
$plugin-&amp;gt;version = 2011062800;  // YYYYMMDDHH (year, month, day, 24-hr time)&lt;br /&gt;
$plugin-&amp;gt;requires = 2010112400; // YYYYMMDDHH (This is the release version for Moodle 2.0)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This file contains object field definitions that denote the full [[Frankenstyle|frankenstyle]] component name in the form of &#039;&#039;plugintype_pluginname&#039;&#039; and the version number of the block, along with the minimum version of Moodle that must be installed in order to use it. Please note that the object being used here is &#039;&#039;always&#039;&#039; called &#039;&#039;&#039;$plugin&#039;&#039;&#039;, and that you do not need to create this object yourself within the version file. Note also we don&#039;t include a closing &amp;quot;?&amp;gt;&amp;quot; tag. This is intentional, and a [[Coding_style#PHP_tags | workaround for whitespace issues]].&lt;br /&gt;
&lt;br /&gt;
The exact Moodle version of a release can be found in [[Releases]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== I Just Hear Static ==&lt;br /&gt;
In order to get our block to actually display something on screen, we need to add one more method to our class (before the final closing brace in our file). The new code is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;  &lt;br /&gt;
  public function get_content() {&lt;br /&gt;
    if ($this-&amp;gt;content !== null) {&lt;br /&gt;
      return $this-&amp;gt;content;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;content         =  new stdClass;&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;text   = &#039;The content of our SimpleHTML block!&#039;;&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
    return $this-&amp;gt;content;&lt;br /&gt;
  }&lt;br /&gt;
}   // Here&#039;s the closing bracket for the class definition&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Add your block to the front page!&#039;&#039;&#039;&lt;br /&gt;
Don&#039;t forget (especially if you&#039;re a new Moodle user) to add your block to the front page. Turn Editing On, and add your block to the page.&lt;br /&gt;
&lt;br /&gt;
It can&#039;t get any simpler than that, can it? Let&#039;s dissect this method to see what&#039;s going on...&lt;br /&gt;
&lt;br /&gt;
First of all, there is a check that returns the current value of [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]] if it&#039;s not NULL; otherwise we proceed with &amp;quot;computing&amp;quot; it. Since the computation is potentially a time-consuming operation and it &#039;&#039;&#039;will&#039;&#039;&#039; be called several times for each block (Moodle works that way internally), we take a precaution and include this time-saver.&lt;br /&gt;
Supposing the content had not been computed before (it was NULL), we then define it from scratch. The code speaks for itself there, so there isn&#039;t much to say. Just keep in mind that we can use HTML both in the text &#039;&#039;&#039;and&#039;&#039;&#039; in the footer, if we want to.&lt;br /&gt;
&lt;br /&gt;
It&#039;s worth mentioning that this is not the only type of content a block can output. You can also create lists and hierarchical trees, which are better suited for certain types of output, such as menus. These different content types have an impact on the content object and how it is constructed. For more information, see [[Blocks/Appendix A#.24this-.3Econtent_type|Appendix A]]&lt;br /&gt;
&lt;br /&gt;
At this point our block should be capable of being automatically installed in Moodle and added to courses; visit your administration page to install it (Click &amp;quot;Notifications&amp;quot; under the Site Administration Block) and after seeing it in action come back to continue our tutorial.&lt;br /&gt;
&lt;br /&gt;
== Configure That Out ==&lt;br /&gt;
&lt;br /&gt;
The current version of our block doesn&#039;t really do much; it just displays a fixed message, which is not very useful. What we&#039;d really like to do is allow the teachers to customize what goes into the block. This, in block-speak, is called &amp;quot;instance configuration&amp;quot;. Basic instance configuration is automatic in Moodle 2.0; if you put any page with blocks on it into &amp;quot;editing mode&amp;quot;, you will notice that each block has an edit button in its title bar. Clicking on this will take you to the block configuration form. The settings that Moodle adds to this form by default relate to the block&#039;s appearance and position on Moodle pages. &lt;br /&gt;
&lt;br /&gt;
We can extend this configuration form, and add custom preferences fields, so that users can better tailor our block to a given task or page. To extend the configuration form, create the file &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/&#039;&#039;&#039;edit_form.php&#039;&#039;&#039;&amp;lt;/span&amp;gt;, and fill it with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
class block_simplehtml_edit_form extends block_edit_form {&lt;br /&gt;
        &lt;br /&gt;
    protected function specific_definition($mform) {&lt;br /&gt;
        &lt;br /&gt;
        // Section header title according to language file.&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;header&#039;, &#039;configheader&#039;, get_string(&#039;blocksettings&#039;, &#039;block&#039;));&lt;br /&gt;
&lt;br /&gt;
        // A sample string variable with a default value.&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;config_text&#039;, get_string(&#039;blockstring&#039;, &#039;block_simplehtml&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;config_text&#039;, &#039;default value&#039;);&lt;br /&gt;
        $mform-&amp;gt;setType(&#039;config_text&#039;, PARAM_RAW);        &lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first line declares a class that inherits &#039;&#039;&#039;from block_edit_form&#039;&#039;&#039;, and this allows Moodle to identify the code to execute in the configuration page. The &#039;&#039;&#039;specific_definition()&#039;&#039;&#039; method is where your form elements are defined, and these take the same format as with the standard [[lib/formslib.php_Form_Definition|Moodle form library]].  Within our specific_definition method, we have created a header, and an input field which will accept text to be used within the block. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; You might want extend language file for your block (lang/en/block_simplehtml.php) and add a value for &amp;quot;blockstring&amp;quot; defined in a code above.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; All your field names need to start with &amp;quot;config_&amp;quot;, otherwise they will not be saved and will not be available within the block via [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]]. &lt;br /&gt;
&lt;br /&gt;
So once our instance configuration form has been saved, we can use the inputted text within the block like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (! empty($this-&amp;gt;config-&amp;gt;text)) {&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;text = $this-&amp;gt;config-&amp;gt;text;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]] is available in all block methods &#039;&#039;except&#039;&#039; [[Blocks/Appendix_A#init.28.29|init()]]. This is because [[Blocks/Appendix_A#init.28.29|init()]] is called immediately as the block is being created, with the purpose of setting things up, so [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]] has not yet been instantiated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note about Checkbox:&#039;&#039;&#039; You cannot use the &#039;checkbox&#039; element in the form (once set it will stay set). You must use advcheckbox instead. &lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== The Specialists ==&lt;br /&gt;
&lt;br /&gt;
Implementing instance configuration for the block&#039;s contents was good enough to whet our appetite, but who wants to stop there? Why not customize the block&#039;s title, too?&lt;br /&gt;
&lt;br /&gt;
Why not, indeed. Well, our first attempt to achieve this is natural enough: let&#039;s add another field to &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;edit_form.php&#039;&#039;&#039;&#039;&#039;. Here goes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    // A sample string variable with a default value.&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;config_title&#039;, get_string(&#039;blocktitle&#039;, &#039;block_simplehtml&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;config_title&#039;, &#039;default value&#039;);&lt;br /&gt;
    $mform-&amp;gt;setType(&#039;config_title&#039;, PARAM_TEXT);        &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We save the edited file, go to a course, edit the title of the block and... nothing happens! The instance configuration is saved correctly, all right (editing it once more proves that) but it&#039;s not being displayed. All we get is just the simple &amp;quot;SimpleHTML&amp;quot; title.&lt;br /&gt;
&lt;br /&gt;
That&#039;s not too weird, if we think back a bit. Do you remember that [[Blocks/Appendix_A#init.28.29|init()]] method, where we set [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]]? We didn&#039;t actually change its value from then, and [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]] is definitely not the same as &#039;&#039;&#039;$this-&amp;gt;config-&amp;gt;title&#039;&#039;&#039; (to Moodle, at least). What we need is a way to update [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]] with the value in the instance configuration. But as we said a bit earlier, we can use [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]] in all methods &#039;&#039;except&#039;&#039; [[Blocks/Appendix_A#init.28.29|init()]]! So what can we do?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pull out another ace from our sleeve, and add this small method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function specialization() {&lt;br /&gt;
    if (isset($this-&amp;gt;config)) {&lt;br /&gt;
        if (empty($this-&amp;gt;config-&amp;gt;title)) {&lt;br /&gt;
            $this-&amp;gt;title = get_string(&#039;defaulttitle&#039;, &#039;block_simplehtml&#039;);            &lt;br /&gt;
        } else {&lt;br /&gt;
            $this-&amp;gt;title = $this-&amp;gt;config-&amp;gt;title;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (empty($this-&amp;gt;config-&amp;gt;text)) {&lt;br /&gt;
            $this-&amp;gt;config-&amp;gt;text = get_string(&#039;defaulttext&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
        }    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aha, here&#039;s what we wanted to do all along! But what&#039;s going on with the [[Blocks/Appendix_A#specialization.28.29| specialization()]] method?&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;magic&amp;quot; method has actually a very nice property: it&#039;s &#039;&#039;guaranteed&#039;&#039; to be automatically called by Moodle as soon as our instance configuration is loaded and available (that is, immediately after [[Blocks/Appendix_A#init.28.29|init()]] is called). That means before the block&#039;s content is computed for the first time, and indeed before &#039;&#039;anything&#039;&#039; else is done with the block. Thus, providing a [[Blocks/Appendix_A#specialization.28.29| specialization()]] method is the natural choice for any configuration data that needs to be acted upon or made available &amp;quot;as soon as possible&amp;quot;, as in this case.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Now You See Me, Now You Don&#039;t ==&lt;br /&gt;
&lt;br /&gt;
Now would be a good time to mention another nifty technique that can be used in blocks, and which comes in handy quite often. Specifically, it may be the case that our block will have something interesting to display some of the time; but in some other cases, it won&#039;t have anything useful to say. An example here would be the &amp;quot;Recent Activity&amp;quot; block, in the case where no recent activity in fact exists. &lt;br /&gt;
&lt;br /&gt;
However in that case the block chooses to explicitly inform you of the lack of said activity, which is arguably useful. It would be nice, then, to be able to have our block &amp;quot;disappear&amp;quot; if it&#039;s not needed to display it.&lt;br /&gt;
&lt;br /&gt;
This is indeed possible, and the way to do it is to make sure that after the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method is called, the block has no content to display. This means that all fields in $this-&amp;gt;content should be equal to the empty string (&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;). In the case of our HTML-based block, these fields are $this-&amp;gt;content-&amp;gt;text and $this-&amp;gt;content-&amp;gt;footer. Moodle performs this check by calling the block&#039;s [[Blocks/Appendix_A#is_empty.28.29| is_empty()]] method, and if the block is indeed empty then it is not displayed at all.&lt;br /&gt;
&lt;br /&gt;
Note that the exact value of the block&#039;s title and the presence or absence of a [[Blocks/Appendix_A#hide_header.28.29| hide_header()]] method do &#039;&#039;not&#039;&#039; affect this behavior. A block is considered empty if it has no content, irrespective of anything else.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== We Are Legion ==&lt;br /&gt;
&lt;br /&gt;
Right now our block is fully configurable, both in title and content. It&#039;s so versatile, in fact, that we could make pretty much anything out of it. It would be really nice to be able to add multiple blocks of this type to a single course. And, as you might have guessed, doing that is as simple as adding another small method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function instance_allow_multiple() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Moodle that it should allow any number of instances of the SimpleHTML block in any course. After saving the changes to our file, Moodle immediately allows us to add multiple copies of the block without further ado!&lt;br /&gt;
&lt;br /&gt;
Please note that even if a block itself allows multiple instances in the same page, the administrator still has the option of disallowing such behavior. This setting can be set separately for each block from the Administration / Configuration / Blocks page.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== The Effects of Globalization ==&lt;br /&gt;
&lt;br /&gt;
Configuring each block instance with its own personal data is cool enough, but sometimes administrators need some way to &amp;quot;touch&amp;quot; all instances of a specific block at the same time. In the case of our SimpleHTML block, a few settings that would make sense to apply to all instances aren&#039;t that hard to come up with. &lt;br /&gt;
&lt;br /&gt;
For example, we might want to limit the contents of each block to only so many characters, or we might have a setting that filters HTML out of the block&#039;s contents, only allowing pure text in. Granted, such a feature wouldn&#039;t win us any awards for naming our block &amp;quot;SimpleHTML&amp;quot; but some tormented administrator somewhere might actually find it useful.&lt;br /&gt;
&lt;br /&gt;
This kind of configuration is called &amp;quot;global configuration&amp;quot; and applies only to a specific block type (all instances of that block type are affected, however).  Implementing such configuration for our block is quite similar to implementing the instance configuration. We will now see how to implement the second example, having a setting that only allows text and not HTML in the block&#039;s contents. To enable global configuration for the block, we create a new file, &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;settings.php&#039;&#039;&#039;&#039;&#039;, and populate it with form field definitions for each setting, which Moodle will use to generate and handle a global settings form.  This is quite similar in concept to how we generated the instance configuration form earlier, but the actual code used to generate the form and fields is somewhat different.&lt;br /&gt;
&lt;br /&gt;
Place the following in your settings.php file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$settings-&amp;gt;add(new admin_setting_heading(&lt;br /&gt;
            &#039;headerconfig&#039;,&lt;br /&gt;
            get_string(&#039;headerconfig&#039;, &#039;block_simplehtml&#039;),&lt;br /&gt;
            get_string(&#039;descconfig&#039;, &#039;block_simplehtml&#039;)&lt;br /&gt;
        ));&lt;br /&gt;
&lt;br /&gt;
$settings-&amp;gt;add(new admin_setting_configcheckbox(&lt;br /&gt;
            &#039;simplehtml/Allow_HTML&#039;,&lt;br /&gt;
            get_string(&#039;labelallowhtml&#039;, &#039;block_simplehtml&#039;),&lt;br /&gt;
            get_string(&#039;descallowhtml&#039;, &#039;block_simplehtml&#039;),&lt;br /&gt;
            &#039;0&#039;&lt;br /&gt;
        ));    &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, to generate a global configuration form, we simply create admin setting objects and add them to an array. This array is then stepped over to create the settings form, and the inputted data is automatically saved to the database. Full details of the setting types available and how to add them can be found under [[Admin_settings#Individual_settings]].&lt;br /&gt;
&lt;br /&gt;
We&#039;ve now created a header and checkbox form element to accept configuration details from the site admin. You should pay extra attention to the name of our checkbox element, &#039;&#039;&#039; &#039;simplehtml/Allow_HTML&#039; &#039;&#039;&#039;, as it specifies not only the name of the configuration option, but also how it should be stored. If you simply specify a name for the config option, it will be stored in the global $CFG object, and in the &#039;&#039;&amp;lt;prefix&amp;gt;_config&#039;&#039; database table. This will make your config variable available immediately via $CFG without requiring an additional database call, but will also increase the size of the $CFG object. In addition, we must prefix the variable with the name of our block, otherwise we run the risk of our config variable sharing its name with a similar variable in another plugin, or within Moodle itself.&lt;br /&gt;
&lt;br /&gt;
The preferred method of storing your block&#039;s configuration data is to prefix each config variable name in your settings.php file with your block&#039;s name, followed by a slash ( / ), and the name of the configuration variable, as we have done above. If you write your settings.php file in this way, then your variables will be stored in the &#039;&#039;&amp;lt;prefix&amp;gt;_config_plugin&#039;&#039; table, under your block&#039;s name. Your config data will still be available via a &#039;&#039;&#039;get_config()&#039;&#039;&#039; call, and name collision will be impossible between plugins.&lt;br /&gt;
&lt;br /&gt;
Finally, if you&#039;re wondering why there are two language tags specified for each element, the first tag is for the element&#039;s label or primary text, and the second tag is for its description. And that&#039;s it. Pretty easy, huh?&lt;br /&gt;
&lt;br /&gt;
=== Enabling Global Configuration ===&lt;br /&gt;
{{Moodle 2.4}}Since version 2.4, the following line must be added to the /blocks/simplehtml/block_simplehtml.php file in order to enable global configuration:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    function has_config() {return true;}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This line tells Moodle that the block has a settings.php file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE FOR UPGRADERS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You&#039;ll notice that the settings.php file and parsed element names replaces Moodle&#039;s old storage method, wherein it would send all the configuration data to your block&#039;s [[Blocks/Appendix_A#config_save.28.29|config_save()]] method, and allow you to override how the data is saved. The [[Blocks/Appendix_A#config_save.28.29|config_save()]] method is no longer used in Moodle 2.x; however the [[Blocks/Appendix_A#instance_config_save.28.29|instance_config_save()]] method is very much alive and well, as you will see shortly.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
=== Accessing Global Config Data  ===&lt;br /&gt;
&lt;br /&gt;
Now that we have global data defined for the plugin, we need to know how to access it within our code.  If you saved your config variables in the global namespace, you can access them from the global $CFG object, like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$allowHTML = $CFG-&amp;gt;Allow_HTML;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If, as recommended, you saved your config variables in a custom namespace for your block, then you can access them via a call to &#039;&#039;&#039;get_config()&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$allowHTML = get_config(&#039;simplehtml&#039;, &#039;Allow_HTML&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
=== Rolling It All Together ===&lt;br /&gt;
&lt;br /&gt;
OK, so we now have an instance configuration form that allows users to enter custom content text for a block, and a global configuration option that dictates whether or not that user should be allowed to enter HTML tags as part of the content. Now we just need to tie the two together. But if Moodle takes care of the form processing for our instance configuration in edit_form.php, how can we capture it and remove the HTML tags where required?&lt;br /&gt;
&lt;br /&gt;
Well, fortunately, there is a way this can be done.  By overriding the [[Blocks/Appendix_A#instance_config_save.28.29| instance_config_save()]] method in our block class, we can modify the way in which instance configuration data is stored after input. The default implementation is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function instance_config_save($data) {&lt;br /&gt;
  $data = stripslashes_recursive($data);&lt;br /&gt;
  $this-&amp;gt;config = $data;&lt;br /&gt;
  return set_field(&#039;block_instance&#039;, &lt;br /&gt;
                   &#039;configdata&#039;,&lt;br /&gt;
                    base64_encode(serialize($data)),&lt;br /&gt;
                   &#039;id&#039;, &lt;br /&gt;
                   $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may look intimidating at first (what&#039;s all this stripslashes_recursive() and base64_encode() and serialize() stuff?) but do not despair; we won&#039;t have to touch any of it. We will only add some extra validation code in the beginning and then instruct Moodle to additionally call this default implementation to do the actual storing of the data. Specifically, we will add a method to our class which goes like this:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function instance_config_save($data) {&lt;br /&gt;
  if(get_config(&#039;simplehtml&#039;, &#039;Allow_HTML&#039;) == &#039;1&#039;) {&lt;br /&gt;
    $data-&amp;gt;text = strip_tags($data-&amp;gt;text);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // And now forward to the default implementation defined in the parent class&lt;br /&gt;
  return parent::instance_config_save($data);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(This example assumes you are using a custom namespace for the block.)&lt;br /&gt;
&lt;br /&gt;
At last! Now the administrator has absolute power of life and death over what type of content is allowed in our &amp;quot;SimpleHTML&amp;quot; block! Absolute? Well... not exactly. In fact, if we think about it for a while, it will become apparent that if at some point in time HTML is allowed and some blocks have saved their content with HTML included, and afterwards the administrator changes the setting to &amp;quot;off&amp;quot;, this will only prevent subsequent content changes from including HTML. Blocks which already had HTML in their content would continue to display it!&lt;br /&gt;
&lt;br /&gt;
Following that train of thought, the next stop is realizing that we wouldn&#039;t have this problem if we had chosen the lazy approach a while back, because in that case we would &amp;quot;sanitize&amp;quot; each block&#039;s content just before it was displayed. &lt;br /&gt;
&lt;br /&gt;
The only thing we can do with the eager approach is strip all the tags from the content of all SimpleHTML instances as soon as the admin setting is changed to &amp;quot;HTML off&amp;quot;; but even then, turning the setting back to &amp;quot;HTML on&amp;quot; won&#039;t bring back the tags we stripped away. On the other hand, the lazy approach might be slower, but it&#039;s more versatile; we can choose whether to strip or keep the HTML before displaying the content, and we won&#039;t lose it at all if the admin toggles the setting off and on again. Isn&#039;t the life of a developer simple and wonderful?&lt;br /&gt;
&lt;br /&gt;
=== Exercise === &lt;br /&gt;
We will let this part of the tutorial come to a close with the obligatory exercise for the reader: &lt;br /&gt;
In order to have the SimpleHTML block work &amp;quot;correctly&amp;quot;, find out how to strengthen the eager approach to strip out all tags from the existing configuration of all instances of our block, &#039;&#039;&#039;or&#039;&#039;&#039; go back and implement the lazy approach instead. &lt;br /&gt;
(Hint: Do that in the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Eye Candy ==&lt;br /&gt;
&lt;br /&gt;
Our block is just about complete functionally, so now let&#039;s take a look at some of the tricks we can use to make its behavior customized in a few more useful ways.&lt;br /&gt;
&lt;br /&gt;
First of all, there are a couple of ways we can adjust the visual aspects of our block. For starters, it might be useful to create a block that doesn&#039;t display a header (title) at all. You can see this effect in action in the Course Description block that comes with Moodle. This behavior is achieved by, you guessed it, adding one more method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function hide_header() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more note here: we cannot just set an empty title inside the block&#039;s [[Blocks/Appendix_A#init.28.29| init()]] method; it&#039;s necessary for each block to have a unique, non-empty title after [[Blocks/Appendix_A#init.28.29| init()]] is called so that Moodle can use those titles to differentiate between all of the installed blocks.&lt;br /&gt;
&lt;br /&gt;
Next, we can affect some properties of the actual HTML that will be used to print our block. Each block is fully contained within a &amp;amp;lt;div&amp;amp;gt; or &amp;amp;lt;table&amp;amp;gt; elements, inside which all the HTML for that block is printed. We can instruct Moodle to add HTML attributes with specific values to that container. This is generally done to give us freedom to customize the end result using CSS (this is in fact done by default as we&#039;ll see below).&lt;br /&gt;
&lt;br /&gt;
The default behavior of this feature in our case will modify our block&#039;s &amp;quot;class&amp;quot; HTML attribute by appending the value &amp;quot;block_simplehtml&amp;quot; (the prefix &amp;quot;block_&amp;quot; followed by the name of our block, lowercased). We can then use that class to make CSS selectors in our theme to alter this block&#039;s visual style (for example, &amp;quot;.block_simplehtml { border: 1px black solid}&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To change the default behavior, we will need to define a method which returns an associative array of attribute names and values. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function html_attributes() {&lt;br /&gt;
    $attributes = parent::html_attributes(); // Get default values&lt;br /&gt;
    $attributes[&#039;class&#039;] .= &#039; block_&#039;. $this-&amp;gt;name(); // Append our class to class attribute&lt;br /&gt;
    return $attributes;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This results in the block having all its normal HTML attributes, as inherited from the base block class, plus our additional class name. We can now use this class name to change the style of the block, add JavaScript events to it via YUI, and so on. And for one final elegant touch,  we have not set the class to the hard-coded value &amp;quot;block_simplehtml&amp;quot;, but instead used the [[Blocks/Appendix_A#name.28.29| name()]] method to make it dynamically match our block&#039;s name.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Authorized Personnel Only ==&lt;br /&gt;
&lt;br /&gt;
Some blocks are useful in some circumstances, but not in others. An example of this would be the &amp;quot;Social Activities&amp;quot; block, which is useful in courses with the &amp;quot;social&amp;quot; course format, but not courses with the &amp;quot;weeks&amp;quot; format. What we need to be able to do is limit our block&#039;s availability, so that it can only be selected on pages where its content or abilities are appropriate.&lt;br /&gt;
&lt;br /&gt;
Moodle allows us to declare which page formats a block is available on, and enforces these restrictions as set by the block&#039;s developer at all times. The information is given to Moodle as a standard associative array, with each key corresponding to a page format and defining a boolean value (true/false) that declares whether the block should be allowed to appear in that page format.&lt;br /&gt;
&lt;br /&gt;
Notice the deliberate use of the term &#039;&#039;page&#039;&#039; instead of &#039;&#039;course&#039;&#039; in the above paragraph. This is because in Moodle 1.5 and onwards, blocks can be displayed in any page that supports them. The best example of such pages are the course pages, but we are not restricted to them. For instance, the quiz view page (the first one we see when we click on the name of the quiz) also supports blocks.&lt;br /&gt;
&lt;br /&gt;
The format names we can use for the pages derive from the name of the script which is actually used to display that page. For example, when we are looking at a course, the script is &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/course/view.php&amp;lt;/span&amp;gt; (this is evident from the browser&#039;s address line). Thus, the format name of that page is &#039;&#039;&#039;course-view&#039;&#039;&#039;. It follows easily that the format name for a quiz view page is &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039;. This rule of thumb does have a few exceptions, however:&lt;br /&gt;
&lt;br /&gt;
# The format name for the front page of Moodle is &#039;&#039;&#039;site-index&#039;&#039;&#039;.&lt;br /&gt;
# The format name for courses is actually not just &#039;&#039;&#039;course-view&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; it is &amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;course-view-weeks&#039;&#039;&#039;, &#039;&#039;&#039;course-view-topics&#039;&#039;&#039;, etc.&lt;br /&gt;
# Even though there is no such page, the format name &#039;&#039;&#039;all&#039;&#039;&#039; can be used as a catch-all option.&lt;br /&gt;
&lt;br /&gt;
We can include as many format names as we want in our definition of the applicable formats. Each format can be allowed or disallowed, and there are also three more rules that help resolve the question &amp;quot;is this block allowed into this page or not?&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
# Prefixes of a format name will match that format name; for example, &#039;&#039;&#039;mod&#039;&#039;&#039; will match all the activity modules. &#039;&#039;&#039;course-view&#039;&#039;&#039; will match any course, regardless of the course format. And finally, &#039;&#039;&#039;site&#039;&#039;&#039; will also match the front page (remember that its full format name is &#039;&#039;&#039;site-index&#039;&#039;&#039;).&lt;br /&gt;
# The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, &#039;&#039;&#039;mod&#039;&#039;&#039;, &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; and &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; all match the quiz view page. But if all three are present, &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; will take precedence over the other two because it is a better match.&lt;br /&gt;
# The character &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; can be used in place of any word. For example, &#039;&#039;&#039;mod&#039;&#039;&#039; and &#039;&#039;&#039;mod-*&#039;&#039;&#039; are equivalent. At the time of this document&#039;s writing, there is no actual reason to utilize this &amp;quot;wildcard matching&amp;quot; feature, but it exists for future usage.&lt;br /&gt;
# The order that the format names appear does not make any difference.&lt;br /&gt;
All of the above are enough to make the situation sound complex, so let&#039;s look at some specific examples. First of all, to have our block appear &#039;&#039;&#039;only&#039;&#039;&#039; in the site front page, we would use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
public function applicable_formats() {&lt;br /&gt;
  return array(&#039;site&#039; =&amp;gt; true);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Since &#039;&#039;&#039;all&#039;&#039;&#039; is missing, the block is disallowed from appearing in &#039;&#039;any&#039;&#039; course format; but then &#039;&#039;&#039;site&#039;&#039;&#039; is set to TRUE, so it&#039;s explicitly allowed to appear in the site front page (remember that &#039;&#039;&#039;site&#039;&#039;&#039; matches &#039;&#039;&#039;site-index&#039;&#039;&#039; because it&#039;s a prefix).&lt;br /&gt;
&lt;br /&gt;
For another example, if we wanted to allow the block to appear in all course formats &#039;&#039;except&#039;&#039; social, and also to &#039;&#039;not&#039;&#039; be allowed anywhere but in courses, we would use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
public function applicable_formats() {&lt;br /&gt;
  return array(&lt;br /&gt;
           &#039;course-view&#039; =&amp;gt; true, &lt;br /&gt;
    &#039;course-view-social&#039; =&amp;gt; false);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time, we first allow the block to appear in all courses and then we explicitly disallow the social format.&lt;br /&gt;
For our final, most complicated example, suppose that a block can be displayed in the site front page, in courses (but not social courses) and also when we are viewing any activity module, &#039;&#039;except&#039;&#039; quiz. This would be:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function applicable_formats() {&lt;br /&gt;
  return array(&lt;br /&gt;
           &#039;site-index&#039; =&amp;gt; true,&lt;br /&gt;
          &#039;course-view&#039; =&amp;gt; true, &lt;br /&gt;
   &#039;course-view-social&#039; =&amp;gt; false,&lt;br /&gt;
                  &#039;mod&#039; =&amp;gt; true, &lt;br /&gt;
             &#039;mod-quiz&#039; =&amp;gt; false&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is not difficult to realize that the above accomplishes the objective if we remember that there is a &amp;quot;best match&amp;quot; policy to determine the end result.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Responding to Cron ==&lt;br /&gt;
&lt;br /&gt;
It is possible to have our block respond to the global Moodle cron process; we can have a method that is run at regular intervals regardless of user interaction. There are two parts to this. Firstly we need to define a new function within our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function cron() {&lt;br /&gt;
    mtrace( &amp;quot;Hey, my cron script is running&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
    // do something&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039;&lt;br /&gt;
If you don&#039;t return true in your cron function, the lastcron field in the blocks table will not be updated and as a result, your cron function will be called every time the cron runs!&lt;br /&gt;
&lt;br /&gt;
Then we will need to set the (minimum) execution interval for our cron function. Prior to Moodle 2.0, this was achieved by setting the value of a block&#039;s $this-&amp;gt;cron field, via the init() method. This is now achieved by adding an additional line to our &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;version.php&#039;&#039;&#039;&#039;&#039; file. Open it up and add the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $plugin-&amp;gt;cron = 300;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cron intervals are set in seconds, so the above line will set our minimum execution interval to 5 minutes. However, the function can only be called as frequently as cron has been set to run in the Moodle installation. So if our block is set to wait at least 5 minutes between runs, as in this example, but Moodle&#039;s cron system is only set to run every 24 hours, then our block is going to be waiting a lot longer between runs than we expected!&lt;br /&gt;
&lt;br /&gt;
Remember that if we change any values in the version file or block file we &#039;&#039;&#039;must&#039;&#039;&#039; bump the version number and visit the Notifications page to upgrade the block, otherwise they will be ignored.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039;&lt;br /&gt;
The block cron is designed to call the cron script for that block &#039;&#039;&#039;type&#039;&#039;&#039; only. That is, cron does not care about individual instances of blocks. Inside your cron function &#039;&#039;$this&#039;&#039; is defined, but it has almost nothing in it (only title and content fields are populated). If you need to execute cron for individual instances it is your own responsibility to iterate over them in the block&#039;s cron function. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function cron() {&lt;br /&gt;
&lt;br /&gt;
    global $DB; // Global database object&lt;br /&gt;
&lt;br /&gt;
    // Get the instances of the block&lt;br /&gt;
    $instances = $DB-&amp;gt;get_records( &#039;block_instances&#039;, array(&#039;blockname&#039;=&amp;gt;&#039;simplehtml&#039;) );&lt;br /&gt;
&lt;br /&gt;
    // Iterate over the instances&lt;br /&gt;
    foreach ($instances as $instance) {&lt;br /&gt;
&lt;br /&gt;
        // Recreate block object&lt;br /&gt;
        $block = block_instance(&#039;simplehtml&#039;, $instance);&lt;br /&gt;
&lt;br /&gt;
        // $block is now the equivalent of $this in &#039;normal&#039; block&lt;br /&gt;
        // usage, e.g.&lt;br /&gt;
        $someconfigitem = $block-&amp;gt;config-&amp;gt;item2;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TIP: This also means that creating a block is a possible way to create code that can respond to cron with a reasonably low overhead. No actual instances of the block are required.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Additional Content Types == &lt;br /&gt;
&lt;br /&gt;
=== Lists ===&lt;br /&gt;
&lt;br /&gt;
In this final part of the guide we will briefly discuss several additional capabilities of Moodle&#039;s block system, namely the ability to create blocks that display different kinds of content to the user. The first of these creates a list of options and displays them to the user.  This list is displayed with one item per line, and an optional image (icon) next to the item. An example of such a &#039;&#039;list block&#039;&#039; is the standard Moodle &amp;quot;admin&amp;quot; block, which illustrates all the points discussed in this section.&lt;br /&gt;
&lt;br /&gt;
As we have seen so far, blocks use two properties of [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]]: &amp;quot;text&amp;quot; and &amp;quot;footer&amp;quot;. The text is displayed as-is as the block content, and the footer is displayed below the content in a smaller font size. List blocks use $this-&amp;gt;content-&amp;gt;footer in the exact same way, but they ignore $this-&amp;gt;content-&amp;gt;text.&lt;br /&gt;
&lt;br /&gt;
Instead, Moodle expects such blocks to set two other properties when the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method is called: $this-&amp;gt;content-&amp;gt;items and $this-&amp;gt;content-&amp;gt;icons. $this-&amp;gt;content-&amp;gt;items should be a numerically indexed array containing elements that represent the HTML for each item in the list that is going to be displayed. Usually these items will be HTML anchor tags which provide links to some page. $this-&amp;gt;content-&amp;gt;icons should also be a numerically indexed array, with exactly as many items as $this-&amp;gt;content-&amp;gt;items has. Each of these items should be a fully qualified HTML &amp;lt;img&amp;gt; tag, with &amp;quot;src&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;width&amp;quot; and &amp;quot;alt&amp;quot; attributes. Obviously, it makes sense to keep the images small and of a uniform size. We would recommend standard 16x16 images for this purpose.&lt;br /&gt;
&lt;br /&gt;
In order to tell Moodle that we want to have a list block instead of the standard text block, we need to make a small change to our block class declaration. Instead of extending class &#039;&#039;&#039;block_base&#039;&#039;&#039;, our block will extend class &#039;&#039;&#039;block_list&#039;&#039;&#039;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
class block_my_menu extends block_list {&lt;br /&gt;
     // The init() method does not need to change at all&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition to making this change, we must of course also modify the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method to construct the [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]] variable as discussed above:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
public function get_content() {&lt;br /&gt;
  if ($this-&amp;gt;content !== null) {&lt;br /&gt;
    return $this-&amp;gt;content;&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  $this-&amp;gt;content         = new stdClass;&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;items  = array();&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;icons  = array();&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;items[] = html_writer::tag(&#039;a&#039;, &#039;Menu Option 1&#039;, array(&#039;href&#039; =&amp;gt; &#039;some_file.php&#039;));&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;icons[] = html_writer::empty_tag(&#039;img&#039;, array(&#039;src&#039; =&amp;gt; &#039;images/icons/1.gif&#039;, &#039;class&#039; =&amp;gt; &#039;icon&#039;));&lt;br /&gt;
&lt;br /&gt;
  // Add more list items here&lt;br /&gt;
 &lt;br /&gt;
  return $this-&amp;gt;content;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To summarise, if we want to create a list block instead of a text block, we just need to change the block class declaration and the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method. Adding the mandatory [[Blocks/Appendix_A#init.28.29| init()]] method as discussed earlier will then give us our first list block in no time!&lt;br /&gt;
&lt;br /&gt;
=== Trees ===&lt;br /&gt;
&lt;br /&gt;
As of 23rd December 2011, this functionality remains inoperable in all Moodle 2.x versions. It appears that classes are missing from the code base. This has been added to the tracker at the URL below. Please upvote this issue if you require this functionality.&lt;br /&gt;
&lt;br /&gt;
[http://tracker.moodle.org/browse/MDL-28289 Visit this issue on the tracker @ MDL28289]&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Database support ==&lt;br /&gt;
In case we need to have a database table that holds some specific information used within our block, we will need to create the file &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;install.xml&#039;&#039;&#039;&#039;&#039; with the table schema contained within it.&lt;br /&gt;
&lt;br /&gt;
To create the install.xml file, use the [[XMLDB editor]]. See [[Database_FAQ#XMLDB|Database FAQ &amp;gt; XMLDB]] for further details.&lt;br /&gt;
&lt;br /&gt;
Up-to-date documentation on upgrading our block, as well as providing new capabilities and events to the system, can be found under [https://docs.moodle.org/dev/Installing_and_upgrading_plugin_database_tables#install.php Installing and Upgrading Plugin Database Tables]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Blocks Advanced]] A continuation of this tutorial.&lt;br /&gt;
* [http://dev.moodle.org/mod/resource/view.php?id=48 Unit 7 of the Introduction to Moodle Programming course] is a follow up to this course. (But you should follow the forum discussions of that course closely as there are still some bugs and inconsistencies.)&lt;br /&gt;
* Daniel Neis Araujo&#039;s [https://github.com/danielneis/moodle-block_newblock NEWBLOCK template].&lt;br /&gt;
&lt;br /&gt;
== Appendices ==&lt;br /&gt;
&lt;br /&gt;
The appendices have been moved to separate pages:&lt;br /&gt;
&lt;br /&gt;
* Appendix A: [[Blocks/Appendix A|&#039;&#039;block_base&#039;&#039; Reference]] &lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Blocks]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
&lt;br /&gt;
[[es:Desarrollo de bloques]]&lt;br /&gt;
[[ja:開発:ブロック]]&lt;br /&gt;
[[:en:Blocks|Blocks]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=49193</id>
		<title>Blocks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=49193"/>
		<updated>2016-01-05T14:15:05Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Updated version.php according with MDL-48494 (Moodle 3.0).&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&#039;&#039;&#039; A Step-by-step Guide To Creating Blocks &#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Original Author: Jon Papaioannou ([mailto:pj@moodle.org pj@moodle.org])&lt;br /&gt;
&lt;br /&gt;
Updated to Moodle 2.0 and above by: Greg J Preece ([mailto:greg.preece@blackboard.com greg.preece@blackboard.com])&lt;br /&gt;
&lt;br /&gt;
Note: the latest information about how to develop a new module (not only a block) can be found in [[NEWMODULE Documentation]] and [https://github.com/moodlehq/moodle-mod_newmodule here], where a full module template code is available.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
The present document serves as a guide to developers who want to create their own blocks for use in Moodle. It applies to the 2.0 development version of Moodle (and any newer) &#039;&#039;&#039;only&#039;&#039;&#039;, as the blocks API changed significantly enough to warrant new documentation. Those wishing to read the old tutorial for Moodles 1.5 to 1.9 can find it under [[Blocks/Blocks for 1.5 to 1.9| Blocks for 1.5 to 1.9]].&lt;br /&gt;
&lt;br /&gt;
The guide is written as an interactive course which aims to develop a configurable, multi-purpose block that displays arbitrary HTML. It&#039;s targeted mainly at people with little experience with Moodle or programming in general and aims to show how easy it is to create new blocks for Moodle. A certain small amount of PHP programming knowledge is still required, though. &lt;br /&gt;
&lt;br /&gt;
Experienced developers and those who just want a &#039;&#039;&#039;programmer&#039;s reference&#039;&#039;&#039; text should refer to [[Blocks/Appendix_A| Appendix A]] because the main guide has a rather low concentration of pure information in the text.&lt;br /&gt;
&lt;br /&gt;
== Basic Concepts ==&lt;br /&gt;
&lt;br /&gt;
Through this guide, we will be following the creation of an &amp;quot;HTML&amp;quot; block from scratch in order to demonstrate most of the block features at our disposal. Our block will be named &amp;quot;SimpleHTML&amp;quot;. This does not constrain us regarding the name of the actual directory on the server where the files for our block will be stored, but for consistency we will follow the practice of using the lowercased form &amp;quot;simplehtml&amp;quot; in any case where such a name is required. &lt;br /&gt;
&lt;br /&gt;
Whenever we refer to a file or directory name which contains &amp;quot;simplehtml&amp;quot;, it&#039;s important to remember that &#039;&#039;only&#039;&#039; the &amp;quot;simplehtml&amp;quot; part is up to us to change; the rest is standardised and essential for Moodle to work correctly.&lt;br /&gt;
&lt;br /&gt;
Whenever a file&#039;s path is mentioned in this guide, it will always start with a slash. This refers to the Moodle home directory; all files and directories will be referred to with respect to that directory.&lt;br /&gt;
&lt;br /&gt;
== Ready, Set, Go! ==&lt;br /&gt;
&lt;br /&gt;
To define a &amp;quot;block&amp;quot; in Moodle, in the most basic case we need to provide just four PHP files. Remember, in this example we are creating a block called &#039;simplehtml&#039;, replace &#039;simplehtml&#039; with the name of your custom block. The four files should be located in blocks/simplehtml and are:&lt;br /&gt;
&lt;br /&gt;
=== block_simplehtml.php ===&lt;br /&gt;
&lt;br /&gt;
This file will hold the class definition for the block, and is used both to manage it as a plugin and to render it onscreen.&lt;br /&gt;
&lt;br /&gt;
We start by creating the main object file, &#039;block_simplehtml.php&#039;. We then begin coding the block:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
class block_simplehtml extends block_base {&lt;br /&gt;
    public function init() {&lt;br /&gt;
        $this-&amp;gt;title = get_string(&#039;simplehtml&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // The PHP tag and the curly bracket for the class definition &lt;br /&gt;
    // will only be closed after there is another function added in the next section.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first line is our block class definition; it must be named exactly in the manner shown. Again, only the &amp;quot;simplehtml&amp;quot; part can (and indeed must) change; everything else is standardised.&lt;br /&gt;
&lt;br /&gt;
Our class is then given a small method: [[Blocks/Appendix_A#init.28.29| init()]]. This is essential for all blocks, and its purpose is to give values to any class member variables that need instantiating. &lt;br /&gt;
&lt;br /&gt;
In this very basic example, we only want to set [[Blocks/Appendix_A#.24this-.3Etitle| $this-&amp;gt;title]], which is the title displayed in the header of our block. We can set it to whatever we like; in this case it&#039;s set to read the actual title from the language file mentioned below, which is then distributed along with the block. I&#039;ll skip ahead a bit here and say that if you want your block to display &#039;&#039;&#039;no&#039;&#039;&#039; title at all, then you should set this to any descriptive value you want (but &#039;&#039;&#039;not&#039;&#039;&#039; make it an empty string). We will later see [[Blocks#Eye_Candy|how to disable the title&#039;s display]].&lt;br /&gt;
&lt;br /&gt;
=== db/access.php ===&lt;br /&gt;
&lt;br /&gt;
This file will hold the new capabilities created by the block.&lt;br /&gt;
&lt;br /&gt;
Moodle 2.4 onwards introduced the capabilities addinstance and myaddinstance for core blocks. They were introduced so that it was possible to control the use of individual blocks. These capabilities should also be added to your custom block, so in this case to the file blocks/simplehtml/db/access.php. If your block is not going to be used in the &#039;My Moodle page&#039; (ie, your applicable_formats function (discussed later) has &#039;my&#039; set to false.) then the myaddinstance capability is not required. The following is the capabilities array and how it should look for any new blocks.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
    $capabilities = array(&lt;br /&gt;
&lt;br /&gt;
    &#039;block/simplehtml:myaddinstance&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_SYSTEM,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;user&#039; =&amp;gt; CAP_ALLOW&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
        &#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/my:manageblocks&#039;&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    &#039;block/simplehtml:addinstance&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039; =&amp;gt; RISK_SPAM | RISK_XSS,&lt;br /&gt;
&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_BLOCK,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array(&lt;br /&gt;
            &#039;editingteacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;manager&#039; =&amp;gt; CAP_ALLOW&lt;br /&gt;
        ),&lt;br /&gt;
&lt;br /&gt;
        &#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/site:manageblocks&#039;&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== lang/en/block_simplehtml.php ===&lt;br /&gt;
&lt;br /&gt;
This is the English language file for your block. If you are not an English speaker, you can replace &#039;en&#039; with your appropriate language code. All language files for blocks go under the /lang subfolder of the block&#039;s installation folder.&lt;br /&gt;
&lt;br /&gt;
Moodle 2.0 and above require a name for our plugin to show in the upgrading page. We set this value, along with the capabilities we created and any other language strings we wish to use within the block, in a language package as previously mentioned (the same file where we put our string for the plugin title).&lt;br /&gt;
&lt;br /&gt;
The capabilities added above need descriptions for pages that allow setting of capabilities. These should also be added to the language file.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Simple HTML block&#039;;&lt;br /&gt;
$string[&#039;simplehtml&#039;] = &#039;Simple HTML&#039;;&lt;br /&gt;
$string[&#039;simplehtml:addinstance&#039;] = &#039;Add a new simple HTML block&#039;;&lt;br /&gt;
$string[&#039;simplehtml:myaddinstance&#039;] = &#039;Add a new simple HTML block to the My Moodle page&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== version.php ===&lt;br /&gt;
&lt;br /&gt;
This file will hold version information for the plugin, along &#039;&#039;&#039;with other advanced parameters&#039;&#039;&#039; (not covered here - see [[version.php]] if you want &#039;&#039;&#039;more details&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
Prior to Moodle 2.0, version details for blocks were stored as class fields; as of Moodle 2.0 these are stored in a file called version.php, stored under &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;version.php&#039;&#039;&#039;&#039;&#039;. The version file is very simple indeed, containing only a few field definitions, depending on your needs. Here is an example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$plugin-&amp;gt;component = &#039;block_simplehtml&#039;;  // Recommended since 2.0.2 (MDL-26035). Required since 3.0 (MDL-48494)&lt;br /&gt;
$plugin-&amp;gt;version = 2011062800;  // YYYYMMDDHH (year, month, day, 24-hr time)&lt;br /&gt;
$plugin-&amp;gt;requires = 2010112400; // YYYYMMDDHH (This is the release version for Moodle 2.0)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This file contains object field definitions that denote the full [[Frankenstyle|frankenstyle]] component name in the form of &#039;&#039;plugintype_pluginname&#039;&#039; and the version number of the block, along with the minimum version of Moodle that must be installed in order to use it. Please note that the object being used here is &#039;&#039;always&#039;&#039; called &#039;&#039;&#039;$plugin&#039;&#039;&#039;, and that you do not need to create this object yourself within the version file. Note also we don&#039;t include a closing &amp;quot;?&amp;gt;&amp;quot; tag. This is intentional, and a [[Coding_style#PHP_tags | workaround for whitespace issues]].&lt;br /&gt;
&lt;br /&gt;
The exact Moodle version of a release can be found in [[Releases]].&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== I Just Hear Static ==&lt;br /&gt;
In order to get our block to actually display something on screen, we need to add one more method to our class (before the final closing brace in our file). The new code is:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;  &lt;br /&gt;
  public function get_content() {&lt;br /&gt;
    if ($this-&amp;gt;content !== null) {&lt;br /&gt;
      return $this-&amp;gt;content;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $this-&amp;gt;content         =  new stdClass;&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;text   = &#039;The content of our SimpleHTML block!&#039;;&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
    return $this-&amp;gt;content;&lt;br /&gt;
  }&lt;br /&gt;
}   // Here&#039;s the closing bracket for the class definition&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Add your block to the front page!&#039;&#039;&#039;&lt;br /&gt;
Don&#039;t forget (especially if you&#039;re a new Moodle user) to add your block to the front page. Turn Editing On, and add your block to the page.&lt;br /&gt;
&lt;br /&gt;
It can&#039;t get any simpler than that, can it? Let&#039;s dissect this method to see what&#039;s going on...&lt;br /&gt;
&lt;br /&gt;
First of all, there is a check that returns the current value of [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]] if it&#039;s not NULL; otherwise we proceed with &amp;quot;computing&amp;quot; it. Since the computation is potentially a time-consuming operation and it &#039;&#039;&#039;will&#039;&#039;&#039; be called several times for each block (Moodle works that way internally), we take a precaution and include this time-saver.&lt;br /&gt;
Supposing the content had not been computed before (it was NULL), we then define it from scratch. The code speaks for itself there, so there isn&#039;t much to say. Just keep in mind that we can use HTML both in the text &#039;&#039;&#039;and&#039;&#039;&#039; in the footer, if we want to.&lt;br /&gt;
&lt;br /&gt;
It&#039;s worth mentioning that this is not the only type of content a block can output. You can also create lists and hierarchical trees, which are better suited for certain types of output, such as menus. These different content types have an impact on the content object and how it is constructed. For more information, see [[Blocks/Appendix A#.24this-.3Econtent_type|Appendix A]]&lt;br /&gt;
&lt;br /&gt;
At this point our block should be capable of being automatically installed in Moodle and added to courses; visit your administration page to install it (Click &amp;quot;Notifications&amp;quot; under the Site Administration Block) and after seeing it in action come back to continue our tutorial.&lt;br /&gt;
&lt;br /&gt;
== Configure That Out ==&lt;br /&gt;
&lt;br /&gt;
The current version of our block doesn&#039;t really do much; it just displays a fixed message, which is not very useful. What we&#039;d really like to do is allow the teachers to customize what goes into the block. This, in block-speak, is called &amp;quot;instance configuration&amp;quot;. Basic instance configuration is automatic in Moodle 2.0; if you put any page with blocks on it into &amp;quot;editing mode&amp;quot;, you will notice that each block has an edit button in its title bar. Clicking on this will take you to the block configuration form. The settings that Moodle adds to this form by default relate to the block&#039;s appearance and position on Moodle pages. &lt;br /&gt;
&lt;br /&gt;
We can extend this configuration form, and add custom preferences fields, so that users can better tailor our block to a given task or page. To extend the configuration form, create the file &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/blocks/simplehtml/&#039;&#039;&#039;edit_form.php&#039;&#039;&#039;&amp;lt;/span&amp;gt;, and fill it with the following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
class block_simplehtml_edit_form extends block_edit_form {&lt;br /&gt;
        &lt;br /&gt;
    protected function specific_definition($mform) {&lt;br /&gt;
        &lt;br /&gt;
        // Section header title according to language file.&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;header&#039;, &#039;configheader&#039;, get_string(&#039;blocksettings&#039;, &#039;block&#039;));&lt;br /&gt;
&lt;br /&gt;
        // A sample string variable with a default value.&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;text&#039;, &#039;config_text&#039;, get_string(&#039;blockstring&#039;, &#039;block_simplehtml&#039;));&lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;config_text&#039;, &#039;default value&#039;);&lt;br /&gt;
        $mform-&amp;gt;setType(&#039;config_text&#039;, PARAM_RAW);        &lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The first line declares a class that inherits &#039;&#039;&#039;from block_edit_form&#039;&#039;&#039;, and this allows Moodle to identify the code to execute in the configuration page. The &#039;&#039;&#039;specific_definition()&#039;&#039;&#039; method is where your form elements are defined, and these take the same format as with the standard [[lib/formslib.php_Form_Definition|Moodle form library]].  Within our specific_definition method, we have created a header, and an input field which will accept text to be used within the block. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039; You might want extend language file for your block (lang/en/block_simplehtml.php) and add a value for &amp;quot;blockstring&amp;quot; defined in a code above.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;IMPORTANT:&#039;&#039;&#039; All your field names need to start with &amp;quot;config_&amp;quot;, otherwise they will not be saved and will not be available within the block via [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]]. &lt;br /&gt;
&lt;br /&gt;
So once our instance configuration form has been saved, we can use the inputted text within the block like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (! empty($this-&amp;gt;config-&amp;gt;text)) {&lt;br /&gt;
    $this-&amp;gt;content-&amp;gt;text = $this-&amp;gt;config-&amp;gt;text;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]] is available in all block methods &#039;&#039;except&#039;&#039; [[Blocks/Appendix_A#init.28.29|init()]]. This is because [[Blocks/Appendix_A#init.28.29|init()]] is called immediately as the block is being created, with the purpose of setting things up, so [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]] has not yet been instantiated.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note about Checkbox:&#039;&#039;&#039; You cannot use the &#039;checkbox&#039; element in the form (once set it will stay set). You must use advcheckbox instead. &lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== The Specialists ==&lt;br /&gt;
&lt;br /&gt;
Implementing instance configuration for the block&#039;s contents was good enough to whet our appetite, but who wants to stop there? Why not customize the block&#039;s title, too?&lt;br /&gt;
&lt;br /&gt;
Why not, indeed. Well, our first attempt to achieve this is natural enough: let&#039;s add another field to &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;edit_form.php&#039;&#039;&#039;&#039;&#039;. Here goes:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    // A sample string variable with a default value.&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;text&#039;, &#039;config_title&#039;, get_string(&#039;blocktitle&#039;, &#039;block_simplehtml&#039;));&lt;br /&gt;
    $mform-&amp;gt;setDefault(&#039;config_title&#039;, &#039;default value&#039;);&lt;br /&gt;
    $mform-&amp;gt;setType(&#039;config_title&#039;, PARAM_TEXT);        &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We save the edited file, go to a course, edit the title of the block and... nothing happens! The instance configuration is saved correctly, all right (editing it once more proves that) but it&#039;s not being displayed. All we get is just the simple &amp;quot;SimpleHTML&amp;quot; title.&lt;br /&gt;
&lt;br /&gt;
That&#039;s not too weird, if we think back a bit. Do you remember that [[Blocks/Appendix_A#init.28.29|init()]] method, where we set [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]]? We didn&#039;t actually change its value from then, and [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]] is definitely not the same as &#039;&#039;&#039;$this-&amp;gt;config-&amp;gt;title&#039;&#039;&#039; (to Moodle, at least). What we need is a way to update [[Blocks/Appendix_A#.24this-.3Etitle|$this-&amp;gt;title]] with the value in the instance configuration. But as we said a bit earlier, we can use [[Blocks/Appendix_A#.24this-.3Econfig| $this-&amp;gt;config]] in all methods &#039;&#039;except&#039;&#039; [[Blocks/Appendix_A#init.28.29|init()]]! So what can we do?&lt;br /&gt;
&lt;br /&gt;
Let&#039;s pull out another ace from our sleeve, and add this small method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function specialization() {&lt;br /&gt;
    if (isset($this-&amp;gt;config)) {&lt;br /&gt;
        if (empty($this-&amp;gt;config-&amp;gt;title)) {&lt;br /&gt;
            $this-&amp;gt;title = get_string(&#039;defaulttitle&#039;, &#039;block_simplehtml&#039;);            &lt;br /&gt;
        } else {&lt;br /&gt;
            $this-&amp;gt;title = $this-&amp;gt;config-&amp;gt;title;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if (empty($this-&amp;gt;config-&amp;gt;text)) {&lt;br /&gt;
            $this-&amp;gt;config-&amp;gt;text = get_string(&#039;defaulttext&#039;, &#039;block_simplehtml&#039;);&lt;br /&gt;
        }    &lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Aha, here&#039;s what we wanted to do all along! But what&#039;s going on with the [[Blocks/Appendix_A#specialization.28.29| specialization()]] method?&lt;br /&gt;
&lt;br /&gt;
This &amp;quot;magic&amp;quot; method has actually a very nice property: it&#039;s &#039;&#039;guaranteed&#039;&#039; to be automatically called by Moodle as soon as our instance configuration is loaded and available (that is, immediately after [[Blocks/Appendix_A#init.28.29|init()]] is called). That means before the block&#039;s content is computed for the first time, and indeed before &#039;&#039;anything&#039;&#039; else is done with the block. Thus, providing a [[Blocks/Appendix_A#specialization.28.29| specialization()]] method is the natural choice for any configuration data that needs to be acted upon or made available &amp;quot;as soon as possible&amp;quot;, as in this case.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Now You See Me, Now You Don&#039;t ==&lt;br /&gt;
&lt;br /&gt;
Now would be a good time to mention another nifty technique that can be used in blocks, and which comes in handy quite often. Specifically, it may be the case that our block will have something interesting to display some of the time; but in some other cases, it won&#039;t have anything useful to say. An example here would be the &amp;quot;Recent Activity&amp;quot; block, in the case where no recent activity in fact exists. &lt;br /&gt;
&lt;br /&gt;
However in that case the block chooses to explicitly inform you of the lack of said activity, which is arguably useful. It would be nice, then, to be able to have our block &amp;quot;disappear&amp;quot; if it&#039;s not needed to display it.&lt;br /&gt;
&lt;br /&gt;
This is indeed possible, and the way to do it is to make sure that after the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method is called, the block has no content to display. This means that all fields in $this-&amp;gt;content should be equal to the empty string (&amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;). In the case of our HTML-based block, these fields are $this-&amp;gt;content-&amp;gt;text and $this-&amp;gt;content-&amp;gt;footer. Moodle performs this check by calling the block&#039;s [[Blocks/Appendix_A#is_empty.28.29| is_empty()]] method, and if the block is indeed empty then it is not displayed at all.&lt;br /&gt;
&lt;br /&gt;
Note that the exact value of the block&#039;s title and the presence or absence of a [[Blocks/Appendix_A#hide_header.28.29| hide_header()]] method do &#039;&#039;not&#039;&#039; affect this behavior. A block is considered empty if it has no content, irrespective of anything else.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== We Are Legion ==&lt;br /&gt;
&lt;br /&gt;
Right now our block is fully configurable, both in title and content. It&#039;s so versatile, in fact, that we could make pretty much anything out of it. It would be really nice to be able to add multiple blocks of this type to a single course. And, as you might have guessed, doing that is as simple as adding another small method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function instance_allow_multiple() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This tells Moodle that it should allow any number of instances of the SimpleHTML block in any course. After saving the changes to our file, Moodle immediately allows us to add multiple copies of the block without further ado!&lt;br /&gt;
&lt;br /&gt;
Please note that even if a block itself allows multiple instances in the same page, the administrator still has the option of disallowing such behavior. This setting can be set separately for each block from the Administration / Configuration / Blocks page.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== The Effects of Globalization ==&lt;br /&gt;
&lt;br /&gt;
Configuring each block instance with its own personal data is cool enough, but sometimes administrators need some way to &amp;quot;touch&amp;quot; all instances of a specific block at the same time. In the case of our SimpleHTML block, a few settings that would make sense to apply to all instances aren&#039;t that hard to come up with. &lt;br /&gt;
&lt;br /&gt;
For example, we might want to limit the contents of each block to only so many characters, or we might have a setting that filters HTML out of the block&#039;s contents, only allowing pure text in. Granted, such a feature wouldn&#039;t win us any awards for naming our block &amp;quot;SimpleHTML&amp;quot; but some tormented administrator somewhere might actually find it useful.&lt;br /&gt;
&lt;br /&gt;
This kind of configuration is called &amp;quot;global configuration&amp;quot; and applies only to a specific block type (all instances of that block type are affected, however).  Implementing such configuration for our block is quite similar to implementing the instance configuration. We will now see how to implement the second example, having a setting that only allows text and not HTML in the block&#039;s contents. To enable global configuration for the block, we create a new file, &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;settings.php&#039;&#039;&#039;&#039;&#039;, and populate it with form field definitions for each setting, which Moodle will use to generate and handle a global settings form.  This is quite similar in concept to how we generated the instance configuration form earlier, but the actual code used to generate the form and fields is somewhat different.&lt;br /&gt;
&lt;br /&gt;
Place the following in your settings.php file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
$settings-&amp;gt;add(new admin_setting_heading(&lt;br /&gt;
            &#039;headerconfig&#039;,&lt;br /&gt;
            get_string(&#039;headerconfig&#039;, &#039;block_simplehtml&#039;),&lt;br /&gt;
            get_string(&#039;descconfig&#039;, &#039;block_simplehtml&#039;)&lt;br /&gt;
        ));&lt;br /&gt;
&lt;br /&gt;
$settings-&amp;gt;add(new admin_setting_configcheckbox(&lt;br /&gt;
            &#039;simplehtml/Allow_HTML&#039;,&lt;br /&gt;
            get_string(&#039;labelallowhtml&#039;, &#039;block_simplehtml&#039;),&lt;br /&gt;
            get_string(&#039;descallowhtml&#039;, &#039;block_simplehtml&#039;),&lt;br /&gt;
            &#039;0&#039;&lt;br /&gt;
        ));    &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
As you can see, to generate a global configuration form, we simply create admin setting objects and add them to an array. This array is then stepped over to create the settings form, and the inputted data is automatically saved to the database. Full details of the setting types available and how to add them can be found under [[Admin_settings#Individual_settings]].&lt;br /&gt;
&lt;br /&gt;
We&#039;ve now created a header and checkbox form element to accept configuration details from the site admin. You should pay extra attention to the name of our checkbox element, &#039;&#039;&#039; &#039;simplehtml/Allow_HTML&#039; &#039;&#039;&#039;, as it specifies not only the name of the configuration option, but also how it should be stored. If you simply specify a name for the config option, it will be stored in the global $CFG object, and in the &#039;&#039;&amp;lt;prefix&amp;gt;_config&#039;&#039; database table. This will make your config variable available immediately via $CFG without requiring an additional database call, but will also increase the size of the $CFG object. In addition, we must prefix the variable with the name of our block, otherwise we run the risk of our config variable sharing its name with a similar variable in another plugin, or within Moodle itself.&lt;br /&gt;
&lt;br /&gt;
The preferred method of storing your block&#039;s configuration data is to prefix each config variable name in your settings.php file with your block&#039;s name, followed by a slash ( / ), and the name of the configuration variable, as we have done above. If you write your settings.php file in this way, then your variables will be stored in the &#039;&#039;&amp;lt;prefix&amp;gt;_config_plugin&#039;&#039; table, under your block&#039;s name. Your config data will still be available via a &#039;&#039;&#039;get_config()&#039;&#039;&#039; call, and name collision will be impossible between plugins.&lt;br /&gt;
&lt;br /&gt;
Finally, if you&#039;re wondering why there are two language tags specified for each element, the first tag is for the element&#039;s label or primary text, and the second tag is for its description. And that&#039;s it. Pretty easy, huh?&lt;br /&gt;
&lt;br /&gt;
=== Enabling Global Configuration ===&lt;br /&gt;
{{Moodle 2.4}}Since version 2.4, the following line must be added to the /blocks/simplehtml/block_simplehtml.php file in order to enable global configuration:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
    function has_config() {return true;}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This line tells Moodle that the block has a settings.php file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE FOR UPGRADERS&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
You&#039;ll notice that the settings.php file and parsed element names replaces Moodle&#039;s old storage method, wherein it would send all the configuration data to your block&#039;s [[Blocks/Appendix_A#config_save.28.29|config_save()]] method, and allow you to override how the data is saved. The [[Blocks/Appendix_A#config_save.28.29|config_save()]] method is no longer used in Moodle 2.x; however the [[Blocks/Appendix_A#instance_config_save.28.29|instance_config_save()]] method is very much alive and well, as you will see shortly.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
=== Accessing Global Config Data  ===&lt;br /&gt;
&lt;br /&gt;
Now that we have global data defined for the plugin, we need to know how to access it within our code.  If you saved your config variables in the global namespace, you can access them from the global $CFG object, like so:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$allowHTML = $CFG-&amp;gt;Allow_HTML;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If, as recommended, you saved your config variables in a custom namespace for your block, then you can access them via a call to &#039;&#039;&#039;get_config()&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$allowHTML = get_config(&#039;simplehtml&#039;, &#039;Allow_HTML&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
=== Rolling It All Together ===&lt;br /&gt;
&lt;br /&gt;
OK, so we now have an instance configuration form that allows users to enter custom content text for a block, and a global configuration option that dictates whether or not that user should be allowed to enter HTML tags as part of the content. Now we just need to tie the two together. But if Moodle takes care of the form processing for our instance configuration in edit_form.php, how can we capture it and remove the HTML tags where required?&lt;br /&gt;
&lt;br /&gt;
Well, fortunately, there is a way this can be done.  By overriding the [[Blocks/Appendix_A#instance_config_save.28.29| instance_config_save()]] method in our block class, we can modify the way in which instance configuration data is stored after input. The default implementation is as follows:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function instance_config_save($data) {&lt;br /&gt;
  $data = stripslashes_recursive($data);&lt;br /&gt;
  $this-&amp;gt;config = $data;&lt;br /&gt;
  return set_field(&#039;block_instance&#039;, &lt;br /&gt;
                   &#039;configdata&#039;,&lt;br /&gt;
                    base64_encode(serialize($data)),&lt;br /&gt;
                   &#039;id&#039;, &lt;br /&gt;
                   $this-&amp;gt;instance-&amp;gt;id);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This may look intimidating at first (what&#039;s all this stripslashes_recursive() and base64_encode() and serialize() stuff?) but do not despair; we won&#039;t have to touch any of it. We will only add some extra validation code in the beginning and then instruct Moodle to additionally call this default implementation to do the actual storing of the data. Specifically, we will add a method to our class which goes like this:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function instance_config_save($data) {&lt;br /&gt;
  if(get_config(&#039;simplehtml&#039;, &#039;Allow_HTML&#039;) == &#039;1&#039;) {&lt;br /&gt;
    $data-&amp;gt;text = strip_tags($data-&amp;gt;text);&lt;br /&gt;
  }&lt;br /&gt;
&lt;br /&gt;
  // And now forward to the default implementation defined in the parent class&lt;br /&gt;
  return parent::instance_config_save($data);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
(This example assumes you are using a custom namespace for the block.)&lt;br /&gt;
&lt;br /&gt;
At last! Now the administrator has absolute power of life and death over what type of content is allowed in our &amp;quot;SimpleHTML&amp;quot; block! Absolute? Well... not exactly. In fact, if we think about it for a while, it will become apparent that if at some point in time HTML is allowed and some blocks have saved their content with HTML included, and afterwards the administrator changes the setting to &amp;quot;off&amp;quot;, this will only prevent subsequent content changes from including HTML. Blocks which already had HTML in their content would continue to display it!&lt;br /&gt;
&lt;br /&gt;
Following that train of thought, the next stop is realizing that we wouldn&#039;t have this problem if we had chosen the lazy approach a while back, because in that case we would &amp;quot;sanitize&amp;quot; each block&#039;s content just before it was displayed. &lt;br /&gt;
&lt;br /&gt;
The only thing we can do with the eager approach is strip all the tags from the content of all SimpleHTML instances as soon as the admin setting is changed to &amp;quot;HTML off&amp;quot;; but even then, turning the setting back to &amp;quot;HTML on&amp;quot; won&#039;t bring back the tags we stripped away. On the other hand, the lazy approach might be slower, but it&#039;s more versatile; we can choose whether to strip or keep the HTML before displaying the content, and we won&#039;t lose it at all if the admin toggles the setting off and on again. Isn&#039;t the life of a developer simple and wonderful?&lt;br /&gt;
&lt;br /&gt;
=== Exercise === &lt;br /&gt;
We will let this part of the tutorial come to a close with the obligatory exercise for the reader: &lt;br /&gt;
In order to have the SimpleHTML block work &amp;quot;correctly&amp;quot;, find out how to strengthen the eager approach to strip out all tags from the existing configuration of all instances of our block, &#039;&#039;&#039;or&#039;&#039;&#039; go back and implement the lazy approach instead. &lt;br /&gt;
(Hint: Do that in the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Eye Candy ==&lt;br /&gt;
&lt;br /&gt;
Our block is just about complete functionally, so now let&#039;s take a look at some of the tricks we can use to make its behavior customized in a few more useful ways.&lt;br /&gt;
&lt;br /&gt;
First of all, there are a couple of ways we can adjust the visual aspects of our block. For starters, it might be useful to create a block that doesn&#039;t display a header (title) at all. You can see this effect in action in the Course Description block that comes with Moodle. This behavior is achieved by, you guessed it, adding one more method to our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function hide_header() {&lt;br /&gt;
  return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
One more note here: we cannot just set an empty title inside the block&#039;s [[Blocks/Appendix_A#init.28.29| init()]] method; it&#039;s necessary for each block to have a unique, non-empty title after [[Blocks/Appendix_A#init.28.29| init()]] is called so that Moodle can use those titles to differentiate between all of the installed blocks.&lt;br /&gt;
&lt;br /&gt;
Next, we can affect some properties of the actual HTML that will be used to print our block. Each block is fully contained within a &amp;amp;lt;div&amp;amp;gt; or &amp;amp;lt;table&amp;amp;gt; elements, inside which all the HTML for that block is printed. We can instruct Moodle to add HTML attributes with specific values to that container. This is generally done to give us freedom to customize the end result using CSS (this is in fact done by default as we&#039;ll see below).&lt;br /&gt;
&lt;br /&gt;
The default behavior of this feature in our case will modify our block&#039;s &amp;quot;class&amp;quot; HTML attribute by appending the value &amp;quot;block_simplehtml&amp;quot; (the prefix &amp;quot;block_&amp;quot; followed by the name of our block, lowercased). We can then use that class to make CSS selectors in our theme to alter this block&#039;s visual style (for example, &amp;quot;.block_simplehtml { border: 1px black solid}&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
To change the default behavior, we will need to define a method which returns an associative array of attribute names and values. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function html_attributes() {&lt;br /&gt;
    $attributes = parent::html_attributes(); // Get default values&lt;br /&gt;
    $attributes[&#039;class&#039;] .= &#039; block_&#039;. $this-&amp;gt;name(); // Append our class to class attribute&lt;br /&gt;
    return $attributes;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This results in the block having all its normal HTML attributes, as inherited from the base block class, plus our additional class name. We can now use this class name to change the style of the block, add JavaScript events to it via YUI, and so on. And for one final elegant touch,  we have not set the class to the hard-coded value &amp;quot;block_simplehtml&amp;quot;, but instead used the [[Blocks/Appendix_A#name.28.29| name()]] method to make it dynamically match our block&#039;s name.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Authorized Personnel Only ==&lt;br /&gt;
&lt;br /&gt;
Some blocks are useful in some circumstances, but not in others. An example of this would be the &amp;quot;Social Activities&amp;quot; block, which is useful in courses with the &amp;quot;social&amp;quot; course format, but not courses with the &amp;quot;weeks&amp;quot; format. What we need to be able to do is limit our block&#039;s availability, so that it can only be selected on pages where its content or abilities are appropriate.&lt;br /&gt;
&lt;br /&gt;
Moodle allows us to declare which page formats a block is available on, and enforces these restrictions as set by the block&#039;s developer at all times. The information is given to Moodle as a standard associative array, with each key corresponding to a page format and defining a boolean value (true/false) that declares whether the block should be allowed to appear in that page format.&lt;br /&gt;
&lt;br /&gt;
Notice the deliberate use of the term &#039;&#039;page&#039;&#039; instead of &#039;&#039;course&#039;&#039; in the above paragraph. This is because in Moodle 1.5 and onwards, blocks can be displayed in any page that supports them. The best example of such pages are the course pages, but we are not restricted to them. For instance, the quiz view page (the first one we see when we click on the name of the quiz) also supports blocks.&lt;br /&gt;
&lt;br /&gt;
The format names we can use for the pages derive from the name of the script which is actually used to display that page. For example, when we are looking at a course, the script is &amp;lt;span class=&amp;quot;filename&amp;quot;&amp;gt;/course/view.php&amp;lt;/span&amp;gt; (this is evident from the browser&#039;s address line). Thus, the format name of that page is &#039;&#039;&#039;course-view&#039;&#039;&#039;. It follows easily that the format name for a quiz view page is &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039;. This rule of thumb does have a few exceptions, however:&lt;br /&gt;
&lt;br /&gt;
# The format name for the front page of Moodle is &#039;&#039;&#039;site-index&#039;&#039;&#039;.&lt;br /&gt;
# The format name for courses is actually not just &#039;&#039;&#039;course-view&#039;&#039;&#039;&amp;lt;nowiki&amp;gt;; it is &amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;course-view-weeks&#039;&#039;&#039;, &#039;&#039;&#039;course-view-topics&#039;&#039;&#039;, etc.&lt;br /&gt;
# Even though there is no such page, the format name &#039;&#039;&#039;all&#039;&#039;&#039; can be used as a catch-all option.&lt;br /&gt;
&lt;br /&gt;
We can include as many format names as we want in our definition of the applicable formats. Each format can be allowed or disallowed, and there are also three more rules that help resolve the question &amp;quot;is this block allowed into this page or not?&amp;quot;:&lt;br /&gt;
&lt;br /&gt;
# Prefixes of a format name will match that format name; for example, &#039;&#039;&#039;mod&#039;&#039;&#039; will match all the activity modules. &#039;&#039;&#039;course-view&#039;&#039;&#039; will match any course, regardless of the course format. And finally, &#039;&#039;&#039;site&#039;&#039;&#039; will also match the front page (remember that its full format name is &#039;&#039;&#039;site-index&#039;&#039;&#039;).&lt;br /&gt;
# The more specialized a format name that matches our page is, the higher precedence it has when deciding if the block will be allowed. For example, &#039;&#039;&#039;mod&#039;&#039;&#039;, &#039;&#039;&#039;mod-quiz&#039;&#039;&#039; and &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; all match the quiz view page. But if all three are present, &#039;&#039;&#039;mod-quiz-view&#039;&#039;&#039; will take precedence over the other two because it is a better match.&lt;br /&gt;
# The character &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;*&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; can be used in place of any word. For example, &#039;&#039;&#039;mod&#039;&#039;&#039; and &#039;&#039;&#039;mod-*&#039;&#039;&#039; are equivalent. At the time of this document&#039;s writing, there is no actual reason to utilize this &amp;quot;wildcard matching&amp;quot; feature, but it exists for future usage.&lt;br /&gt;
# The order that the format names appear does not make any difference.&lt;br /&gt;
All of the above are enough to make the situation sound complex, so let&#039;s look at some specific examples. First of all, to have our block appear &#039;&#039;&#039;only&#039;&#039;&#039; in the site front page, we would use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
public function applicable_formats() {&lt;br /&gt;
  return array(&#039;site&#039; =&amp;gt; true);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
Since &#039;&#039;&#039;all&#039;&#039;&#039; is missing, the block is disallowed from appearing in &#039;&#039;any&#039;&#039; course format; but then &#039;&#039;&#039;site&#039;&#039;&#039; is set to TRUE, so it&#039;s explicitly allowed to appear in the site front page (remember that &#039;&#039;&#039;site&#039;&#039;&#039; matches &#039;&#039;&#039;site-index&#039;&#039;&#039; because it&#039;s a prefix).&lt;br /&gt;
&lt;br /&gt;
For another example, if we wanted to allow the block to appear in all course formats &#039;&#039;except&#039;&#039; social, and also to &#039;&#039;not&#039;&#039; be allowed anywhere but in courses, we would use:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
public function applicable_formats() {&lt;br /&gt;
  return array(&lt;br /&gt;
           &#039;course-view&#039; =&amp;gt; true, &lt;br /&gt;
    &#039;course-view-social&#039; =&amp;gt; false);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This time, we first allow the block to appear in all courses and then we explicitly disallow the social format.&lt;br /&gt;
For our final, most complicated example, suppose that a block can be displayed in the site front page, in courses (but not social courses) and also when we are viewing any activity module, &#039;&#039;except&#039;&#039; quiz. This would be:&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function applicable_formats() {&lt;br /&gt;
  return array(&lt;br /&gt;
           &#039;site-index&#039; =&amp;gt; true,&lt;br /&gt;
          &#039;course-view&#039; =&amp;gt; true, &lt;br /&gt;
   &#039;course-view-social&#039; =&amp;gt; false,&lt;br /&gt;
                  &#039;mod&#039; =&amp;gt; true, &lt;br /&gt;
             &#039;mod-quiz&#039; =&amp;gt; false&lt;br /&gt;
  );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It is not difficult to realize that the above accomplishes the objective if we remember that there is a &amp;quot;best match&amp;quot; policy to determine the end result.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Responding to Cron ==&lt;br /&gt;
&lt;br /&gt;
It is possible to have our block respond to the global Moodle cron process; we can have a method that is run at regular intervals regardless of user interaction. There are two parts to this. Firstly we need to define a new function within our block class:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function cron() {&lt;br /&gt;
    mtrace( &amp;quot;Hey, my cron script is running&amp;quot; );&lt;br /&gt;
&lt;br /&gt;
    // do something&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039;&lt;br /&gt;
If you don&#039;t return true in your cron function, the lastcron field in the blocks table will not be updated and as a result, your cron function will be called every time the cron runs!&lt;br /&gt;
&lt;br /&gt;
Then we will need to set the (minimum) execution interval for our cron function. Prior to Moodle 2.0, this was achieved by setting the value of a block&#039;s $this-&amp;gt;cron field, via the init() method. This is now achieved by adding an additional line to our &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;version.php&#039;&#039;&#039;&#039;&#039; file. Open it up and add the following:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $plugin-&amp;gt;cron = 300;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Cron intervals are set in seconds, so the above line will set our minimum execution interval to 5 minutes. However, the function can only be called as frequently as cron has been set to run in the Moodle installation. So if our block is set to wait at least 5 minutes between runs, as in this example, but Moodle&#039;s cron system is only set to run every 24 hours, then our block is going to be waiting a lot longer between runs than we expected!&lt;br /&gt;
&lt;br /&gt;
Remember that if we change any values in the version file or block file we &#039;&#039;&#039;must&#039;&#039;&#039; bump the version number and visit the Notifications page to upgrade the block, otherwise they will be ignored.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;NOTE:&#039;&#039;&#039;&lt;br /&gt;
The block cron is designed to call the cron script for that block &#039;&#039;&#039;type&#039;&#039;&#039; only. That is, cron does not care about individual instances of blocks. Inside your cron function &#039;&#039;$this&#039;&#039; is defined, but it has almost nothing in it (only title and content fields are populated). If you need to execute cron for individual instances it is your own responsibility to iterate over them in the block&#039;s cron function. Example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
public function cron() {&lt;br /&gt;
&lt;br /&gt;
    global $DB; // Global database object&lt;br /&gt;
&lt;br /&gt;
    // Get the instances of the block&lt;br /&gt;
    $instances = $DB-&amp;gt;get_records( &#039;block_instances&#039;, array(&#039;blockname&#039;=&amp;gt;&#039;simplehtml&#039;) );&lt;br /&gt;
&lt;br /&gt;
    // Iterate over the instances&lt;br /&gt;
    foreach ($instances as $instance) {&lt;br /&gt;
&lt;br /&gt;
        // Recreate block object&lt;br /&gt;
        $block = block_instance(&#039;simplehtml&#039;, $instance);&lt;br /&gt;
&lt;br /&gt;
        // $block is now the equivalent of $this in &#039;normal&#039; block&lt;br /&gt;
        // usage, e.g.&lt;br /&gt;
        $someconfigitem = $block-&amp;gt;config-&amp;gt;item2;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
TIP: This also means that creating a block is a possible way to create code that can respond to cron with a reasonably low overhead. No actual instances of the block are required.&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Additional Content Types == &lt;br /&gt;
&lt;br /&gt;
=== Lists ===&lt;br /&gt;
&lt;br /&gt;
In this final part of the guide we will briefly discuss several additional capabilities of Moodle&#039;s block system, namely the ability to create blocks that display different kinds of content to the user. The first of these creates a list of options and displays them to the user.  This list is displayed with one item per line, and an optional image (icon) next to the item. An example of such a &#039;&#039;list block&#039;&#039; is the standard Moodle &amp;quot;admin&amp;quot; block, which illustrates all the points discussed in this section.&lt;br /&gt;
&lt;br /&gt;
As we have seen so far, blocks use two properties of [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]]: &amp;quot;text&amp;quot; and &amp;quot;footer&amp;quot;. The text is displayed as-is as the block content, and the footer is displayed below the content in a smaller font size. List blocks use $this-&amp;gt;content-&amp;gt;footer in the exact same way, but they ignore $this-&amp;gt;content-&amp;gt;text.&lt;br /&gt;
&lt;br /&gt;
Instead, Moodle expects such blocks to set two other properties when the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method is called: $this-&amp;gt;content-&amp;gt;items and $this-&amp;gt;content-&amp;gt;icons. $this-&amp;gt;content-&amp;gt;items should be a numerically indexed array containing elements that represent the HTML for each item in the list that is going to be displayed. Usually these items will be HTML anchor tags which provide links to some page. $this-&amp;gt;content-&amp;gt;icons should also be a numerically indexed array, with exactly as many items as $this-&amp;gt;content-&amp;gt;items has. Each of these items should be a fully qualified HTML &amp;lt;img&amp;gt; tag, with &amp;quot;src&amp;quot;, &amp;quot;height&amp;quot;, &amp;quot;width&amp;quot; and &amp;quot;alt&amp;quot; attributes. Obviously, it makes sense to keep the images small and of a uniform size. We would recommend standard 16x16 images for this purpose.&lt;br /&gt;
&lt;br /&gt;
In order to tell Moodle that we want to have a list block instead of the standard text block, we need to make a small change to our block class declaration. Instead of extending class &#039;&#039;&#039;block_base&#039;&#039;&#039;, our block will extend class &#039;&#039;&#039;block_list&#039;&#039;&#039;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
class block_my_menu extends block_list {&lt;br /&gt;
     // The init() method does not need to change at all&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In addition to making this change, we must of course also modify the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method to construct the [[Blocks/Appendix_A#.24this-.3Econtent| $this-&amp;gt;content]] variable as discussed above:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt; &lt;br /&gt;
public function get_content() {&lt;br /&gt;
  if ($this-&amp;gt;content !== null) {&lt;br /&gt;
    return $this-&amp;gt;content;&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
  $this-&amp;gt;content         = new stdClass;&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;items  = array();&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;icons  = array();&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;footer = &#039;Footer here...&#039;;&lt;br /&gt;
 &lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;items[] = html_writer::tag(&#039;a&#039;, &#039;Menu Option 1&#039;, array(&#039;href&#039; =&amp;gt; &#039;some_file.php&#039;));&lt;br /&gt;
  $this-&amp;gt;content-&amp;gt;icons[] = html_writer::empty_tag(&#039;img&#039;, array(&#039;src&#039; =&amp;gt; &#039;images/icons/1.gif&#039;, &#039;class&#039; =&amp;gt; &#039;icon&#039;));&lt;br /&gt;
&lt;br /&gt;
  // Add more list items here&lt;br /&gt;
 &lt;br /&gt;
  return $this-&amp;gt;content;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To summarise, if we want to create a list block instead of a text block, we just need to change the block class declaration and the [[Blocks/Appendix_A#get_content.28.29| get_content()]] method. Adding the mandatory [[Blocks/Appendix_A#init.28.29| init()]] method as discussed earlier will then give us our first list block in no time!&lt;br /&gt;
&lt;br /&gt;
=== Trees ===&lt;br /&gt;
&lt;br /&gt;
As of 23rd December 2011, this functionality remains inoperable in all Moodle 2.x versions. It appears that classes are missing from the code base. This has been added to the tracker at the URL below. Please upvote this issue if you require this functionality.&lt;br /&gt;
&lt;br /&gt;
[http://tracker.moodle.org/browse/MDL-28289 Visit this issue on the tracker @ MDL28289]&lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
== Database support ==&lt;br /&gt;
In case we need to have a database table that holds some specific information used within our block, we will need to create the file &#039;&#039;/blocks/simplehtml/&#039;&#039;&#039;install.xml&#039;&#039;&#039;&#039;&#039; with the table schema contained within it.&lt;br /&gt;
&lt;br /&gt;
To create the install.xml file, use the [[XMLDB editor]]. See [[Database_FAQ#XMLDB|Database FAQ &amp;gt; XMLDB]] for further details.&lt;br /&gt;
&lt;br /&gt;
Up-to-date documentation on upgrading our block, as well as providing new capabilities and events to the system, can be found under [https://docs.moodle.org/dev/Installing_and_upgrading_plugin_database_tables#install.php Installing and Upgrading Plugin Database Tables]&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Blocks Advanced]] A continuation of this tutorial.&lt;br /&gt;
* [http://dev.moodle.org/mod/resource/view.php?id=48 Unit 7 of the Introduction to Moodle Programming course] is a follow up to this course. (But you should follow the forum discussions of that course closely as there are still some bugs and inconsistencies.)&lt;br /&gt;
* Daniel Neis Araujo&#039;s [https://github.com/danielneis/moodle-block_newblock NEWBLOCK template].&lt;br /&gt;
&lt;br /&gt;
== Appendices ==&lt;br /&gt;
&lt;br /&gt;
The appendices have been moved to separate pages:&lt;br /&gt;
&lt;br /&gt;
* Appendix A: [[Blocks/Appendix A|&#039;&#039;block_base&#039;&#039; Reference]] &lt;br /&gt;
&lt;br /&gt;
{{Top}}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Blocks]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
&lt;br /&gt;
[[es:Desarrollo de bloques]]&lt;br /&gt;
[[ja:開発:ブロック]]&lt;br /&gt;
[[:en:Blocks|Blocks]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Time_API&amp;diff=47658</id>
		<title>Time API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Time_API&amp;diff=47658"/>
		<updated>2015-04-23T06:02:30Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: /* Time API&amp;#039;s for current user */ Improved commenting style, according with https://docs.moodle.org/dev/Coding_style#Inline_comments&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
Internally Moodle always stores all times in unixtime format (number of seconds since epoch) which is independent of timezones.&lt;br /&gt;
&lt;br /&gt;
The Time API is used to display proper date-time depending on user or site timezones.&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
Functions related to time api can be found in lib/moodlelib.php. &lt;br /&gt;
# Time API&#039;s for current user&lt;br /&gt;
#* &#039;&#039;&#039;make_timestamp&#039;&#039;&#039; - Given date-time, it produces a GMT timestamp for current user.&lt;br /&gt;
#* &#039;&#039;&#039;userdate&#039;&#039;&#039; - Gets formatted string that represents a date in user time&lt;br /&gt;
#* &#039;&#039;&#039;usertime&#039;&#039;&#039; - Given a GMT timestamp (seconds since epoch), offsets it by the timezone.  eg 3pm in India is 3pm GMT - 5.5 * 3600 seconds&lt;br /&gt;
#* &#039;&#039;&#039;usergetdate&#039;&#039;&#039; - Given a timestamp in GMT, returns an array that represents the date-time in user time&lt;br /&gt;
#* &#039;&#039;&#039;usergetmidnight&#039;&#039;&#039; - Given a date, return the GMT timestamp of the most recent midnight for the current user.&lt;br /&gt;
#* &#039;&#039;&#039;usertimezone&#039;&#039;&#039; - Returns current user&#039;s timezone&lt;br /&gt;
#* &#039;&#039;&#039;get_user_timezone_offset&#039;&#039;&#039; - Returns user&#039;s timezone difference from GMT in hours&lt;br /&gt;
# System Time API&lt;br /&gt;
#* &#039;&#039;&#039;format_time&#039;&#039;&#039; - Format a date/time (seconds) as weeks, days, hours etc as needed&lt;br /&gt;
#* &#039;&#039;&#039;get_timezone_offset&#039;&#039;&#039; - Systems&#039;s timezone difference from GMT in seconds&lt;br /&gt;
#* &#039;&#039;&#039;dst_changes_for_year&#039;&#039;&#039; -  Calculates the required DST change and returns a Timestamp Array&lt;br /&gt;
#* &#039;&#039;&#039;dst_offset_on&#039;&#039;&#039; - Calculates the Daylight Saving Offset for a given date/time (timestamp)&lt;br /&gt;
#* &#039;&#039;&#039;find_day_in_month&#039;&#039;&#039; - Calculates when the day appears in specific month&lt;br /&gt;
#* &#039;&#039;&#039;days_in_month&#039;&#039;&#039; - Calculate number of days in a given month&lt;br /&gt;
#* &#039;&#039;&#039;dayofweek&#039;&#039;&#039; - Calculate the position in the week of a specific calendar day&lt;br /&gt;
&lt;br /&gt;
==Glossary==&lt;br /&gt;
===Timezone===&lt;br /&gt;
Moodle supports following timezone formats:&lt;br /&gt;
# UTC (specifically UTC−11 to UTC+11)&lt;br /&gt;
# Time offsets from UTC (int +-(0-13) or float +-(0.5-12.5))&lt;br /&gt;
# World timezones (Australia/Perth)&lt;br /&gt;
&lt;br /&gt;
===Location===&lt;br /&gt;
Timezone depends on [[:en:Location]] of the user and can be forced upon by administrator.&lt;br /&gt;
===DST===&lt;br /&gt;
DST is abbreviation of &#039;&#039;&#039;Day light saving&#039;&#039;&#039;. Many countries, and sometimes just certain regions of countries, adopt daylight saving time (also known as &amp;quot;Summer Time&amp;quot;) during part of the year. Moodle automatically calculates DST for current user, depending on user location.&lt;br /&gt;
==Examples==&lt;br /&gt;
===Time API&#039;s for current user===&lt;br /&gt;
Prints a formatted date in user time&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Get current day, month and year for current user.&lt;br /&gt;
$date = usergetdate(time());&lt;br /&gt;
list($d, $m, $y) = array($date[&#039;mday&#039;], $date[&#039;mon&#039;], $date[&#039;year&#039;]);&lt;br /&gt;
// Print formatted date in user time.&lt;br /&gt;
echo userdate(make_timestamp($y, $m), &amp;quot;Current user time&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===System Time API===&lt;br /&gt;
Find start month day&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$now = usergetdate(time());&lt;br /&gt;
echo find_day_in_month($now[&#039;mday&#039;] - 6, $startweekday, $now[&#039;mon&#039;], $now[&#039;year&#039;]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Time_API&amp;diff=47657</id>
		<title>Time API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Time_API&amp;diff=47657"/>
		<updated>2015-04-23T05:59:59Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: /* Timezone */ Fixed typo.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
&lt;br /&gt;
Internally Moodle always stores all times in unixtime format (number of seconds since epoch) which is independent of timezones.&lt;br /&gt;
&lt;br /&gt;
The Time API is used to display proper date-time depending on user or site timezones.&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
Functions related to time api can be found in lib/moodlelib.php. &lt;br /&gt;
# Time API&#039;s for current user&lt;br /&gt;
#* &#039;&#039;&#039;make_timestamp&#039;&#039;&#039; - Given date-time, it produces a GMT timestamp for current user.&lt;br /&gt;
#* &#039;&#039;&#039;userdate&#039;&#039;&#039; - Gets formatted string that represents a date in user time&lt;br /&gt;
#* &#039;&#039;&#039;usertime&#039;&#039;&#039; - Given a GMT timestamp (seconds since epoch), offsets it by the timezone.  eg 3pm in India is 3pm GMT - 5.5 * 3600 seconds&lt;br /&gt;
#* &#039;&#039;&#039;usergetdate&#039;&#039;&#039; - Given a timestamp in GMT, returns an array that represents the date-time in user time&lt;br /&gt;
#* &#039;&#039;&#039;usergetmidnight&#039;&#039;&#039; - Given a date, return the GMT timestamp of the most recent midnight for the current user.&lt;br /&gt;
#* &#039;&#039;&#039;usertimezone&#039;&#039;&#039; - Returns current user&#039;s timezone&lt;br /&gt;
#* &#039;&#039;&#039;get_user_timezone_offset&#039;&#039;&#039; - Returns user&#039;s timezone difference from GMT in hours&lt;br /&gt;
# System Time API&lt;br /&gt;
#* &#039;&#039;&#039;format_time&#039;&#039;&#039; - Format a date/time (seconds) as weeks, days, hours etc as needed&lt;br /&gt;
#* &#039;&#039;&#039;get_timezone_offset&#039;&#039;&#039; - Systems&#039;s timezone difference from GMT in seconds&lt;br /&gt;
#* &#039;&#039;&#039;dst_changes_for_year&#039;&#039;&#039; -  Calculates the required DST change and returns a Timestamp Array&lt;br /&gt;
#* &#039;&#039;&#039;dst_offset_on&#039;&#039;&#039; - Calculates the Daylight Saving Offset for a given date/time (timestamp)&lt;br /&gt;
#* &#039;&#039;&#039;find_day_in_month&#039;&#039;&#039; - Calculates when the day appears in specific month&lt;br /&gt;
#* &#039;&#039;&#039;days_in_month&#039;&#039;&#039; - Calculate number of days in a given month&lt;br /&gt;
#* &#039;&#039;&#039;dayofweek&#039;&#039;&#039; - Calculate the position in the week of a specific calendar day&lt;br /&gt;
&lt;br /&gt;
==Glossary==&lt;br /&gt;
===Timezone===&lt;br /&gt;
Moodle supports following timezone formats:&lt;br /&gt;
# UTC (specifically UTC−11 to UTC+11)&lt;br /&gt;
# Time offsets from UTC (int +-(0-13) or float +-(0.5-12.5))&lt;br /&gt;
# World timezones (Australia/Perth)&lt;br /&gt;
&lt;br /&gt;
===Location===&lt;br /&gt;
Timezone depends on [[:en:Location]] of the user and can be forced upon by administrator.&lt;br /&gt;
===DST===&lt;br /&gt;
DST is abbreviation of &#039;&#039;&#039;Day light saving&#039;&#039;&#039;. Many countries, and sometimes just certain regions of countries, adopt daylight saving time (also known as &amp;quot;Summer Time&amp;quot;) during part of the year. Moodle automatically calculates DST for current user, depending on user location.&lt;br /&gt;
==Examples==&lt;br /&gt;
===Time API&#039;s for current user===&lt;br /&gt;
Prints a formatted date in user time&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//get current day, month and year for current user&lt;br /&gt;
$date = usergetdate(time());&lt;br /&gt;
list($d, $m, $y) = array($date[&#039;mday&#039;], $date[&#039;mon&#039;], $date[&#039;year&#039;]);&lt;br /&gt;
//Print formatted date in user time&lt;br /&gt;
echo userdate(make_timestamp($y, $m), &amp;quot;Current user time&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===System Time API===&lt;br /&gt;
Find start month day&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$now = usergetdate(time());&lt;br /&gt;
echo find_day_in_month($now[&#039;mday&#039;] - 6, $startweekday, $now[&#039;mon&#039;], $now[&#039;year&#039;]);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Automated_code_review&amp;diff=47510</id>
		<title>Automated code review</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Automated_code_review&amp;diff=47510"/>
		<updated>2015-03-15T11:26:06Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Typo&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle issues submitted for review and inclusion into core are examined by our continuous integration (ci) system and checked against various automated tests. We use the automated checks to help improve the code quality in Moodle.&lt;br /&gt;
&lt;br /&gt;
== What is CiBot? ==&lt;br /&gt;
CiBot is our automated code checker and it will run checks against any issues waiting for peer review, sent for integration or requested to be checked by the developer. It will report problems discovered in lines of your patch which you are changing.&lt;br /&gt;
&lt;br /&gt;
== What checks is CiBot carrying out on each issue? ==&lt;br /&gt;
* Verify mergeability, number of commits and branch ages.&lt;br /&gt;
* Require testing instructions.&lt;br /&gt;
* Automated php syntax check using php -l and [https://github.com/moodlehq/moodle-local_ci/tree/master/php_lint these scripts]&lt;br /&gt;
* Automated [https://docs.moodle.org/dev/Coding_style coding style] checks using [https://moodle.org/plugins/view.php?plugin=local_codechecker local_codechecker].&lt;br /&gt;
* Automated [https://docs.moodle.org/dev/Coding_style#Documentation_and_comments PHPDoc] checks using [https://moodle.org/plugins/view.php?plugin=local_moodlecheck local_moodlecheck].&lt;br /&gt;
* Automated [https://docs.moodle.org/dev/Commit_cheat_sheet#Provide_clear_commit_messages commit message] checks using [https://github.com/moodlehq/moodle-local_ci/tree/master/verify_commit_messages these scripts].&lt;br /&gt;
* Automated [http://docs.moodle.org/dev/Upgrade_API upgrade savepoint] checks using [https://github.com/moodlehq/moodle-local_ci/tree/master/check_upgrade_savepoints these scripts].&lt;br /&gt;
* Automated [http://www.jshint.com jshint]  javascript linting checks using the [https://github.com/moodle/moodle/blob/master/.jshintrc .jshintrc] configuration shipped with Moodle&lt;br /&gt;
* Automated [https://github.com/CSSLint/csslint csslint]  CSS linting checks using the [https://github.com/moodle/moodle/blob/master/.csslintrc .csslintrc] configuration shipped with Moodle&lt;br /&gt;
* Automated third party library modification check using [https://github.com/moodlehq/moodle-local_ci/tree/master/thirdparty_check these scripts]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== Will an issue be automatically rejected if cibot checks fail? ==&lt;br /&gt;
No. Developers should strive to have cibot approve every patch submitted, but the integration team will take a pragmatic approach to things like:&lt;br /&gt;
* Occasions where cibot will detect issues present in existing code (see [[#Should coding style issues in existing code be fixed?|next item]])&lt;br /&gt;
* Variations from commit message style which make the commit message more understandable overall&lt;br /&gt;
&lt;br /&gt;
== Should coding style issues in existing code be fixed? ==&lt;br /&gt;
&lt;br /&gt;
In short, please only update lines relating to your own change.&lt;br /&gt;
&lt;br /&gt;
There are some conventions that are not uniformly followed in the code base, many of these are conventions put in place after code was written. Our long term goal is for the entire codebase to follow the conventions, but in general, we don&#039;t want large-scale reformatting of existing code. See [[Coding_style#Policy_about_coding-style_only_fixes]].&lt;br /&gt;
&lt;br /&gt;
=== Example situations ===&lt;br /&gt;
==== Spacing of if statements is incorrect on the line being changed ====&lt;br /&gt;
This can be corrected without affecting existing code, so should be fixed.&lt;br /&gt;
&lt;br /&gt;
==== The line being changed contains an invalid variable name ====&lt;br /&gt;
If correcting this variable would affect other parts of the code not covered by the patch then it&#039;s not reasonable to fix it.&lt;br /&gt;
&lt;br /&gt;
== Requesting CiBot checks an issue ==&lt;br /&gt;
At any time a developer can add the label &#039;cime&#039; to an issue to request it runs it checks against it. The bot [https://github.com/moodlehq/moodle-local_ci/blob/master/tracker_automations/bulk_precheck_issues/criteria/developer_request/query.sh checks for issues with the cime label] every 20mins and runs the checks then remove the cime label. (Note that because it removes the label, it is normal to &#039;create&#039; the label).&lt;br /&gt;
&lt;br /&gt;
Any issue [https://github.com/moodlehq/moodle-local_ci/blob/master/tracker_automations/bulk_precheck_issues/criteria/awaiting_peer_review/query.sh submitted for peer review] or [https://github.com/moodlehq/moodle-local_ci/blob/master/tracker_automations/bulk_precheck_issues/criteria/awaiting_integration/query.sh integration review] will be checked automatically as long as it does not already have the &#039;ci&#039;  label.&lt;br /&gt;
&lt;br /&gt;
== Are additional CiBot checks possible? ==&lt;br /&gt;
Yes. It is planned to add more checks - (see  MDLSITE-3267) and developers are encouraged to suggest new checks in that issue. Note that some limitations exist:&lt;br /&gt;
* The checks should be consistent and completely reproducible&lt;br /&gt;
* The check should complete in minutes not hours (other solutions are in planning for longer term tests)&lt;br /&gt;
&lt;br /&gt;
== The git commit summary  limit is too small ==&lt;br /&gt;
When you overrun the length limit many git tools do not display commits well. See how [https://github.com/moodle/moodle/commits/ea6f5480818c31763f91a90a0cafb6a63ca18117 github truncates ea6f548081] - it ruins the message and makes it harder for you to communicate your change to other developers.&lt;br /&gt;
&lt;br /&gt;
It is acknowledged that its often tricky to get a useful message in such a short space on the first line. However, the coding guidelines for git summary line length were established on the basis of [https://github.com/blog/926-shiny-new-commit-styles industry] [http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/Documentation/SubmittingPatches?id=aad7fb916a10f1065ad23de0c80a4a04bcba8437#n594 best] [http://stackoverflow.com/questions/2290016/git-commit-messages-50-72-formatting practice]. As the [[Coding_style#Git_commits]] mentions, do not be afraid to go into much more detail in your commit body.&lt;br /&gt;
&lt;br /&gt;
Try &amp;lt;pre&amp;gt;git log --oneline --no-merges&amp;lt;/pre&amp;gt; if you want to see how other developers have tried to adapt to this situation.&lt;br /&gt;
&lt;br /&gt;
== Branches based off integration.git ==&lt;br /&gt;
The integration.git repository exists separately from moodle.git intentionally to indicate that its the place that &#039;&#039;&#039;history rewrites will happen&#039;&#039;&#039;. If a branch is based on outdated history which has been rewritten and is later attempted to merge it will result in a  mess (repeated history, attempt to re-introduce previously reverted changes). It is for this reason that we strongly recommend against any branches being created based on the integration.git branches due its changing nature. This problem is emphasised because history rewrites will commonly happen at the end of a weekly cycle, immediately before releasing the changes to moodle.git. &lt;br /&gt;
&lt;br /&gt;
There are some rare cases where basing a branch off integration.git might be sensible:&lt;br /&gt;
* Where the change would have non-trivial conflicts with integration.git changes (e.g. two commits changing the same function)&lt;br /&gt;
* Could not be branched from moodle.git with these conflicts resolved&lt;br /&gt;
If this case applies:&lt;br /&gt;
* CiBot will warn about the branch being based off integration.git&lt;br /&gt;
* The developer is expected to rebase once integration.git changes have been introduced to moodle.git to ensure that history-rewrites will not cause a merge mess&lt;br /&gt;
&lt;br /&gt;
If these case do not apply, we expect that you &#039;&#039;&#039;do not&#039;&#039;&#039; produce your branches based on integration.git.&lt;br /&gt;
&lt;br /&gt;
==Why are issues held up by trivial issues reported which don&#039;t affect the functionality of the change?==&lt;br /&gt;
&lt;br /&gt;
Moodle is a large software project, it is common that 50 different developers will change the same file. Some may produce one fix and never be seen again, others will produce hundreds of fixes. The purpose of our coding conventions is to help all developers communicate with a consistent style so that we can look at all changes and understand their purpose with out getting distracted by changes in style. &lt;br /&gt;
&lt;br /&gt;
While the issues reported might be trivial compared to benefit of the fix, over the long term, communicating your change well through coding and commit conventions might be far more important.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
&amp;quot; programs must be written for people to read, and only incidentally for machines to execute&amp;quot;&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;br /&gt;
― Hal Abelson, Structure and Interpretation of Computer Programs&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Coding style]] and other links in the [[:Category:Coding guidelines|coding guidelines category]]&lt;br /&gt;
&lt;br /&gt;
[[Category:Coding guidelines|Coding style]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=45083</id>
		<title>Git for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=45083"/>
		<updated>2014-06-01T08:55:08Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: /* Cherry-picking a single commit */ Added a short description of a multiple cherry-picking command though the page suggests a different path.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is for helping you get started on Moodle development with Git. For further details of Git, see [[:Category:Git]].&lt;br /&gt;
&lt;br /&gt;
== General workflow ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;A reasonable knowledge of the Git basics is a good idea before you start to use it for development. If you are new to Git, you are encouraged to go to &#039;See also&#039; for some more general reading.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[image:git-pushpull-model.png|right|thumb|400px|Moodle development workflow with Git]]&lt;br /&gt;
In short, the Moodle development with Git looks like this:&lt;br /&gt;
&lt;br /&gt;
* You as the contributor commit changes into your personal repository at your computer&lt;br /&gt;
* You push the changes into your public repository and publish links to your changes in the Moodle Tracker&lt;br /&gt;
* You may ask for a peer review of your code from another developer (preferred but optional)&lt;br /&gt;
* When you are confident of your code you should submit it for integration (Integration request, also sometimes known as a pull request)&lt;br /&gt;
* Moodle integrators pull the changes from your public repository and if they like them, they put them into Moodle integration repository&lt;br /&gt;
* The integrated change is tested and finally pushed into Moodle production repository&lt;br /&gt;
* You update your local repository with all changes from the production repository and the next cycle may start again&lt;br /&gt;
&lt;br /&gt;
This workflow runs in roughly weekly cycles. The integration happens on Monday and the testing on Tuesday. On Wednesday, the production repository moodle.git is usually updated with changes from the last development week.&lt;br /&gt;
&lt;br /&gt;
Most Moodle developers have their public repositories hosted at [http://github.com/ Github]. Alternatively you may want to try [http://gitorious.org Gitorious] or the legendary [http://repo.or.cz repo.or.cz]. In the examples in this guide we assume you&#039;ll set up your public repository at Github.&lt;br /&gt;
&lt;br /&gt;
If you&#039;d like to be added to the developers group in the tracker (which allows you to assign issues to yourself), please send an email to michaeld@moodle.com with your tracker username and a link to an issue where you have contributed a patch.&lt;br /&gt;
&lt;br /&gt;
== Installing Git on your computer ==&lt;br /&gt;
&lt;br /&gt;
Install Git on your computer. Most Linux distributions have Git available as a package to install. If you are on Mac, [http://code.google.com/p/git-osx-installer/ git-osx-installer] installs it in a few clicks.&lt;br /&gt;
&lt;br /&gt;
Immediately after the installation, set your name and contact e-mail. The name and e-mail will become part of your commits and they can&#039;t be changed later once your commits are accepted into the Moodle code. Therefore we ask contributors to use their real names written in capital letters, eg &amp;quot;John Smith&amp;quot; and not &amp;quot;john smith&amp;quot; or even &amp;quot;john5677&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
    git config --global user.name &amp;quot;Your Name&amp;quot;&lt;br /&gt;
    git config --global user.email yourmail@domain.tld&lt;br /&gt;
&lt;br /&gt;
Unless you are the repository maintainer, it is wise to set your Git to not push changes in file permissions:&lt;br /&gt;
&lt;br /&gt;
    git config --global core.filemode false&lt;br /&gt;
&lt;br /&gt;
== Setting-up the public repository ==&lt;br /&gt;
&lt;br /&gt;
1. Go to [http://github.com/ Github] and create an account.&lt;br /&gt;
&lt;br /&gt;
2. Go to the [http://github.com/moodle/moodle official Moodle Github repository] and click on the Fork button. You now have your own Github Moodle repository.&lt;br /&gt;
&lt;br /&gt;
3. Now you need to set up your SSH public key, so you can push to your Github Moodle repository from your local Moodle repository. On Mac you can go on this [http://help.github.com/mac-key-setup/ Github help page]. If you are on another system, go to your Github administration page, to the section SSH Public Keys, and you should see a link to a help page. Done? Good! That was the most difficult part!&lt;br /&gt;
&lt;br /&gt;
== Setting-up the local repository at your computer  ==&lt;br /&gt;
&lt;br /&gt;
Create a local clone repository of your Github repository. In a terminal:&lt;br /&gt;
&lt;br /&gt;
    git clone git://github.com/YOUR_GITHUB_USERNAME/moodle.git LOCALDIR&lt;br /&gt;
&lt;br /&gt;
    (or:  git clone git@github.com:YOUR_GITHUB_USERNAME/moodle.git LOCALDIR)&lt;br /&gt;
&lt;br /&gt;
This command does several jobs for you. It creates a new folder, initializes an empty Git repository in it, sets your Github repository as the remote repository called &#039;origin&#039; and makes a local checkout of the branch &#039;master&#039; from it. The important point to remember now is that your Github repository is aliased as &#039;origin&#039; for your local clone.&lt;br /&gt;
&lt;br /&gt;
Note that the format of the URL here is important. In the first example, the URL starts &amp;quot;git://github.com&amp;quot; and this will give read-only access to the repository at github.com. If you use this URL, the &amp;quot;git push origin&amp;quot; command that appears later in this document will not work. Therefore, if you want to be able to update the &amp;quot;origin&amp;quot; repository, you should use the URL that starts &amp;quot;git@github.com&amp;quot;, i.e. the second of the two &amp;quot;git clone&amp;quot; commands given above. This will give you read and write access to the repository on github.com.&lt;br /&gt;
&lt;br /&gt;
== Keeping your public repository up-to-date ==&lt;br /&gt;
&lt;br /&gt;
[[image:git-sync-github.png|right|thumb|400px|Fetching changes from upstream and pushing them to github]]&lt;br /&gt;
Your fork at Github is not updated automatically. To keep it synced with the upstream Moodle repository, you have to fetch the recent changes from the official moodle.git and push them to your public repository. To avoid problems with this it is strongly recommended that you never modify the standard Moodle branches. &#039;&#039;Remember: never commit directly into master and MOODLE_xx_STABLE branches.&#039;&#039; In other words, always create topic branches to work on. In Gitspeak, the master branch and MOODLE_xx_STABLE branches should be always fast-forwardable.&lt;br /&gt;
&lt;br /&gt;
To keep your public repository up-to-date, we will register remote repository git://git.moodle.org/moodle.git under &#039;upstream&#039; alias. Then we create a script to be run regularly that fetches changes from the upstream repository and pushes them to your public repository. Note that this procedure will not affect your local working directory.&lt;br /&gt;
&lt;br /&gt;
To register the upstream remote:&lt;br /&gt;
&lt;br /&gt;
    cd moodle&lt;br /&gt;
    git remote add upstream git://git.moodle.org/moodle.git&lt;br /&gt;
&lt;br /&gt;
The following commands can be used to keep the standard Moodle branches at your Github repository synced with the upstream repository. You may wish to store them in a script so that you can run it every week after the upstream repository is updated.&lt;br /&gt;
&lt;br /&gt;
    #!/bin/sh&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    for BRANCH in MOODLE_19_STABLE MOODLE_20_STABLE MOODLE_21_STABLE MOODLE_22_STABLE MOODLE_23_STABLE MOODLE_24_STABLE MOODLE_25_STABLE MOODLE_26_STABLE master; do&lt;br /&gt;
        git push origin refs/remotes/upstream/$BRANCH:$BRANCH&lt;br /&gt;
    done&lt;br /&gt;
&lt;br /&gt;
=== How it works ===&lt;br /&gt;
&lt;br /&gt;
The git-fetch command does not modify your current working dir (your checkout). It just downloads all recent changes from a remote repository and stores them into so called remote-tracking branches. The git-push command takes these remote-tracking branches from upstream and pushes them to Github under the same name. Understanding this fully requires a bit knowledge of Git internals - see gitrevisions(7) man page.&lt;br /&gt;
&lt;br /&gt;
Note there is no need to switch the local branch during this. You can even execute this via cron at your machine. Just note that the upstream repository updates typically just once a week.&lt;br /&gt;
&lt;br /&gt;
=== New branches ===&lt;br /&gt;
&lt;br /&gt;
Occasionally, moodle.org will create a new branch that does not exist in your public (e.g. Github.com) repository. If you try to push this new branch, you will see an error such as the following:&lt;br /&gt;
&lt;br /&gt;
    error: unable to push to unqualified destination: MOODLE_99_STABLE&lt;br /&gt;
    The destination refspec neither matches an existing ref on the remote&lt;br /&gt;
    nor begins with refs/, and we are unable to guess a prefix based on the source ref.&lt;br /&gt;
    error: failed to push some refs to &#039;git@github.com:YOUR_GITHUB_USERNAME/moodle.git&#039;&lt;br /&gt;
&lt;br /&gt;
In the above example, &amp;quot;MOODLE_99_STABLE&amp;quot;, is the name of the new branch that does not exist in your public repository. To fix the error, you need to create the new branch on your public repository, using the following commands, replacing &amp;quot;MOODLE_99_STABLE&amp;quot; with the name of the new branch you wish to create:&lt;br /&gt;
&lt;br /&gt;
    git checkout MOODLE_99_STABLE&lt;br /&gt;
    git push origin MOODLE_99_STABLE:MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
The above code will create a new copy of the &amp;quot;MOODLE_99_STABLE&amp;quot; branch in your local repository. If you do not need to keep a local copy of the new branch - and probably you do not need it, you then can remove it from your local repository as follows:&lt;br /&gt;
&lt;br /&gt;
    git checkout master&lt;br /&gt;
    git branch -D MOODLE_99_STABLE&lt;br /&gt;
&lt;br /&gt;
== Preparing a patch ==&lt;br /&gt;
&lt;br /&gt;
As said earlier at this page, you never work on standard Moodle branches directly. Every time you are going to edit something, switch to a local branch. Fork the local branch off the standard branch you think it should be merged to. So if you are working on a patch for 1.9 or 2.0, fork the branch off MOODLE_19_STABLE or MOODLE_20_STABLE, respectively. Patches for the next [[Moodle versions|major version]] should be based on the master branch.&lt;br /&gt;
&lt;br /&gt;
    git checkout -b MDL-xxxxx-nasty-bug origin/master&lt;br /&gt;
&lt;br /&gt;
Note that if you forget to specify the starting point, the branch is based on the currently checked-out branch. It may not be what you want. It is recommended to always specify the starting point.&lt;br /&gt;
&lt;br /&gt;
To check the current branch, run&lt;br /&gt;
&lt;br /&gt;
    git branch&lt;br /&gt;
&lt;br /&gt;
The current branch is highlighted.&lt;br /&gt;
&lt;br /&gt;
Now go and fix the issue with your favorite IDE. Check the status of the files, view the change to be committed and finally commit the change:&lt;br /&gt;
&lt;br /&gt;
    vim filename.php&lt;br /&gt;
    git status&lt;br /&gt;
    git diff&lt;br /&gt;
    git commit -a&lt;br /&gt;
&lt;br /&gt;
Note that this is safe as the commit is recorded just locally, nothing is sent to any server yet (as it would in CVS). To see history of the commits, use&lt;br /&gt;
&lt;br /&gt;
    git log&lt;br /&gt;
&lt;br /&gt;
Once your local branch contains the change (note that it may consists of several patches) and you are happy with it, publish the branch at your public repository:&lt;br /&gt;
&lt;br /&gt;
    git push MDL-xxxxx-nasty-bug&lt;br /&gt;
&lt;br /&gt;
Because we did not specify explicit remote repository, the &#039;origin&#039; is used. Because we did not specify the branch to push, the Git will use the current branch and push it to the remote repository under the same name (by default, this is a subject of your configuration. See push.default config variable).&lt;br /&gt;
&lt;br /&gt;
Now as your branch is published, you can ask Moodle core developers to review it and eventually integrate it into the standard Moodle repository.&lt;br /&gt;
&lt;br /&gt;
=== Checking if a branch has already been merged ===&lt;br /&gt;
&lt;br /&gt;
After some time contributing to Moodle you would have a lot of branches both in your local repository and in your public repository. To prune their list and delete those that were accepted by upstream, use the following&lt;br /&gt;
&lt;br /&gt;
    git fetch upstream                                      (1)&lt;br /&gt;
    git branch --merged upstream/master                     (2)&lt;br /&gt;
    git branch --merged upstream/MOODLE_20_STABLE           (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) fetches the changes from your upstream repository at git.moodle.org (remember that git-fetch does not modify your working dir so it is safe to run it whenever). Command (2) and (3) print all branches that are merged into the upstream master branch and MOODLE_20_STABLE branch, respectively. To delete these local branches, use&lt;br /&gt;
&lt;br /&gt;
    git branch -d MDL-xxxxx-accepted-branch&lt;br /&gt;
&lt;br /&gt;
The similar approach can be used to check the branches published at your origin repository at github.com&lt;br /&gt;
&lt;br /&gt;
    git fetch origin                                        (1)&lt;br /&gt;
    git fetch upstream&lt;br /&gt;
    git branch -r --merged upstream/master                  (2)&lt;br /&gt;
    git branch -r --merged upstream/MOODLE_20_STABLE        (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) makes sure that you have all your branches from github.com recorded as the remote tracking branch locally. Commands (2) and (3) work the same as in the previous example but they list remote tracking branches only ([http://www.kernel.org/pub/software/scm/git/docs/git-branch.html see -r param]). To delete a branch at github.com, use&lt;br /&gt;
&lt;br /&gt;
    git push origin :MDL-xxxx-branch-to-delete&lt;br /&gt;
&lt;br /&gt;
This syntax may look weird to you. However it is pretty logical. The general syntax of the git-push command is&lt;br /&gt;
&lt;br /&gt;
    git push &amp;lt;repository&amp;gt; &amp;lt;source ref&amp;gt;:&amp;lt;target ref&amp;gt;&lt;br /&gt;
&lt;br /&gt;
so deleting a remote branch can be understood as pushing an &amp;quot;empty (null) reference&amp;quot; to it.&lt;br /&gt;
&lt;br /&gt;
== Peer-reviewing someone else&#039;s code ==&lt;br /&gt;
&lt;br /&gt;
To review a branch that someone else pushed into their public repository, you do not need to register a new remote (unless you work with such repository frequently, of course). Let us imagine your friend Alice pushed a work-in-progress branch called &#039;wip-feature&#039; into her Github repository and asked you to review it. You need to know the read-only address of the repository and the name of the branch.&lt;br /&gt;
&lt;br /&gt;
    git fetch git://github.com/alice/moodle.git wip-feature&lt;br /&gt;
&lt;br /&gt;
This will download all required data and will keep the pointer to the tip of the wip-feature branch in a local symbolic reference FETCH_HEAD. To see what&#039;s there on that branch, use&lt;br /&gt;
&lt;br /&gt;
    git log -p FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see how a particular file looks at Alice&#039;s branch&lt;br /&gt;
&lt;br /&gt;
    git show FETCH_HEAD:admin/blocks.php&lt;br /&gt;
&lt;br /&gt;
To create a new local branch called &#039;alice-wip-feature&#039; containing the work by Alice, use&lt;br /&gt;
&lt;br /&gt;
    git checkout -b alice-wip-feature FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To merge Alice&#039;s work into your current branch:&lt;br /&gt;
&lt;br /&gt;
    git merge FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
To see what would be merged into the current branch without actually modifying anything:&lt;br /&gt;
&lt;br /&gt;
    git diff ...FETCH_HEAD&lt;br /&gt;
&lt;br /&gt;
Once you are all set and reviewing code, this [[Peer_reviewing_checklist|checklist]] should prove to be useful.&lt;br /&gt;
&lt;br /&gt;
== Rebasing a branch ==&lt;br /&gt;
&lt;br /&gt;
Rebasing is a process when you cut off the branch from its current start point and transplant it to another point. Let us assume the following history exists:&lt;br /&gt;
&lt;br /&gt;
          A---B---C topic&lt;br /&gt;
         /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
From this point, the result of the command:&lt;br /&gt;
&lt;br /&gt;
    git rebase master topic&lt;br /&gt;
&lt;br /&gt;
would be:&lt;br /&gt;
&lt;br /&gt;
                  A&#039;--B&#039;--C&#039; topic&lt;br /&gt;
                 /&lt;br /&gt;
    D---E---F---G master&lt;br /&gt;
&lt;br /&gt;
and would end with &#039;topic&#039; being your current branch.&lt;br /&gt;
&lt;br /&gt;
You may be asked to rebase your branch submitted for the integration if the submitted branch was based on an outdated commit. The typical case is if you create a new branch as a fork off the upstream master branch on Tuesday. Then on Wednesday, the upstream master branch grows as all changes from the last integration cycle are merged to it. To make diff easy on Github for next weekly pull request review, you want to rebase your branch against the updated master.&lt;br /&gt;
&lt;br /&gt;
    git rebase master MDL-xxxxx-topic-branch&lt;br /&gt;
&lt;br /&gt;
Note that rebasing effectively rewrites the history of the branch. &#039;&#039;&#039;Do not rebase the branch if there is a chance that somebody has already forked it and based their own branch on it.&#039;&#039;&#039; For this reason, many Git tutorials discourage from rebasing any branch that has been published. However in Moodle, all branches submitted for integration are potential subject of rebase (even though we try to not to do it often) and you should not base your own branches on them.&lt;br /&gt;
&lt;br /&gt;
=== Conflicts during rebase ===&lt;br /&gt;
&lt;br /&gt;
During the rebase procedure, conflicts may appear. git-status commands reports the conflicted files. Explore them carefully and fix them in your editor (like you would do with CVS). Then add the files with &#039;git add&#039; command and continue.&lt;br /&gt;
&lt;br /&gt;
    vim conflicted.php&lt;br /&gt;
    git add conflicted.php&lt;br /&gt;
    git rebase --continue&lt;br /&gt;
&lt;br /&gt;
== Applying changes from one branch to another ==&lt;br /&gt;
&lt;br /&gt;
Most bugs are fixed at a stable branch (like MOODLE_20_STABLE) and the fix must be prepared for other branches, too (like MOODLE_21_STABLE and the main development branch - master). In Moodle, we do not merge stable branches into the master one. So usually the contributor prepares at least two branches - with the fix for the stable branch(es) and with the fix for the master branch.&lt;br /&gt;
&lt;br /&gt;
If you have a patch prepared on a local branch (let us say MDL-xxxx-topic_20_STABLE), it is possible to re-apply it to another branch.&lt;br /&gt;
&lt;br /&gt;
=== Cherry-picking a single commit ===&lt;br /&gt;
&lt;br /&gt;
Let us have two local Git repositories ~/public_html/moodle21 containing local installation of Moodle 2.1 and ~/public_html/moodledev with the local installation of most recent development version of Moodle. They both use your public repository at github.com as the origin. You have a branch in moodle21 called MDL-xxxx-topic_21_STABLE that was forked off MOODLE_21_STABLE. It contains one commit. Now you want to re-apply this commit to a branch MDL-xxxx-topic in moodledev.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master            (1)&lt;br /&gt;
    git fetch ../moodle21 MDL-xxxx-topic_21_STABLE          (2)&lt;br /&gt;
    git cherry-pick FETCH_HEAD                              (3)&lt;br /&gt;
&lt;br /&gt;
The command (1) creates new local branch forked off the CONTHERE The command (1) fetches all data needed to re-apply the topic branch and stores the pointer to the tip of that branch to FETCH_HEAD symbolic reference. The command (2) picks the tip of the branch (the top-most commit on it) and tries to apply it on the current branch.&lt;br /&gt;
There is also a variant of the cherry-pick command that supports multiple commits, shortly (see its man page for details): &amp;lt;code bash&amp;gt;$ git cherry-pick A^..B&amp;lt;/code&amp;gt; if you want to include from A - see &#039;&#039;&#039;^&#039;&#039;&#039; - to B, A should be older than B. We will use another approach for cherry-picking multiple commits.&lt;br /&gt;
&lt;br /&gt;
=== Applying a set of patches ===&lt;br /&gt;
&lt;br /&gt;
If the branch MDL-xxxx-topic_21_STABLE from the previous example consists of several commits, it may be easier to use git-format-patch and git-am combo to re-apply the whole set of patches (aka patchset). Firstly you will export all commits from the topic branch to files.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodle21&lt;br /&gt;
    mkdir .patches&lt;br /&gt;
    git format-patch -o .patches MOODLE_21_STABLE..MDL-xxxx-topic_21_STABLE         (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) takes all commits from the topic branch that are not in MOODLE_21_STABLE and exports them one by one to the output directory .patches. Look at the generated files. They contain the patch itself (in diff format) and additional information about the commit. You could eg send these files by email to a friend of yours for peer-review. We will use them in another repository.&lt;br /&gt;
&lt;br /&gt;
    cd ~/public_html/moodledev&lt;br /&gt;
    git checkout -b MDL-xxxx-topic origin/master&lt;br /&gt;
    git am -3 ../moodle21/.patches/*                        (1)&lt;br /&gt;
&lt;br /&gt;
The command (1) applies all the files from the .patches directory. When a patch does not apply cleanly, the command tries fall back on 3-way merge (see the -3 parameter). If conflicts occur during the procedure, you can either deal with them and then use `git am --continue` or abort the whole procedure with `git am --abort`.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
; Moodle forum discussions&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=168094 GIT help needed]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=165236 Best way to manage CONTRIB code with GIT]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167063 Handy Git tip for tracking 3rd-party modules and plugins]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=167730 Moodle Git repositories]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=183409 Git help!! I don&#039;t understand rebase enough...]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=217617 add MOODLE_24_STABLE to github.com repository]&lt;br /&gt;
&lt;br /&gt;
; External resources &lt;br /&gt;
* [http://www.kernel.org/pub/software/scm/git/docs/everyday.html Everyday GIT With 20 Commands Or So]&lt;br /&gt;
* [http://gitref.org/ Git Reference]&lt;br /&gt;
* [http://progit.org/book/ Pro Git book]&lt;br /&gt;
* [http://vimeo.com/14629850 Getting git by Scott Chacon] - an recording of an excellent 1-hour presentation that introducing git, including a simple introduction to what is going on under the hood.&lt;br /&gt;
&lt;br /&gt;
[[Category:Git]]&lt;br /&gt;
&lt;br /&gt;
[[ja:開発者用Git]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=43459</id>
		<title>Events API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Events_API&amp;diff=43459"/>
		<updated>2013-12-29T09:27:20Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: /* Triggering events */ Fixed a typo preventing the work of the hyperlink for the Verb list&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Events 2&lt;br /&gt;
|state = Implementation in progress&lt;br /&gt;
|tracker = MDL-39797 , MDL-39952, MDL-39846&lt;br /&gt;
|discussion = https://moodle.org/mod/forum/discuss.php?d=229425&lt;br /&gt;
|assignee = Backend Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
= What are events? =&lt;br /&gt;
&lt;br /&gt;
Events are atomic pieces of information describing something that happened in Moodle. Events are primarily the result of user actions, but could also be the result of the [[:en:Cron|cron]] process or administration actions [[:en:Administration via command line|undertaken via the command line]].&lt;br /&gt;
&lt;br /&gt;
When an action takes place, an event is created by a [[Core APIs|core API]] or [[Plugins|plugin]]. The Events system then disseminates this event information to observers registered for this event. In this way, the events system acts as a communication backbone throughout the Moodle system.&lt;br /&gt;
&lt;br /&gt;
Event observers can not modify event data or interrupt the dispatching of events, it is a one way communication channel.&lt;br /&gt;
&lt;br /&gt;
= Why is a new events system needed? =&lt;br /&gt;
&lt;br /&gt;
The need to improve the Events system was prompted by a need for a richer and more efficient logging system, however the benefits of this improvement will be useful to other parts of Moodle that observe event information.&lt;br /&gt;
&lt;br /&gt;
* The events need to be more strictly defined if we want to use them for new logging and other advanced use cases. They need to contain a lot more information in a standardised way (such as most fields from current log table and log_actions table).&lt;br /&gt;
* Complex data types were allowed in old events which was causing major problems when serialising/storing/unserializing the data.&lt;br /&gt;
* The logging and events contain similar information and are tiggered at the same places, new events would remove this code duplication. All events should be loggable and all current log entries should be triggered as events.&lt;br /&gt;
* The logging system will become an event observer, listening to all events and directing them to logging storage plugins in a controllable way.&lt;br /&gt;
* It will be possible to subscribe to &#039;*&#039; event, which would allow a system to potentially observe, and selectively deal with, all events. Current handlers do not get event name which makes this problematic.&lt;br /&gt;
* Current event handlers may trigger exceptions during site upgrade which would lead to fatal upgrade problems. The new design eliminates this.&lt;br /&gt;
* Failure in handlers blocked dispatching of subsequent events. Instead problems in new observers would be only logged and execution would continue normally.&lt;br /&gt;
* Current execution of external handlers during DB transactions blocks other handlers. This would be eliminated by in-memory buffer for external events.&lt;br /&gt;
* It would good to have observer priority.&lt;br /&gt;
* Nested events are not dispatched sequentially, it would change the order of events received in lower priority handlers.&lt;br /&gt;
&lt;br /&gt;
= Performance =&lt;br /&gt;
Some basic profiling has been conducted.&lt;br /&gt;
&lt;br /&gt;
There is a general plan to complete pre- and post-implementation testing as development happens. The new system will be imemented in parallel with the old one which should help with comparison of new and old logging and event triggering performance on each page.&lt;br /&gt;
&lt;br /&gt;
Our aim is to trigger more events and log more information, which is going to impact on performance. We hope to offset that impact by improving log storage, simplifying event dispatching and adding other core performance improvements. The proposed class structure of the base event should allow some new advanced techniques, which may also improve performance in some scenarios.&lt;br /&gt;
&lt;br /&gt;
More details will be added to this section soon.&lt;br /&gt;
&lt;br /&gt;
= Events API =&lt;br /&gt;
&lt;br /&gt;
Each plugin will define the events that it can report (trigger) by extending an abstract base class, once for each possible event. This approach will have several benefits.&lt;br /&gt;
; Events will be active objects&lt;br /&gt;
: When they are triggered and possibly after they are reinstantiated (say, when they are retrieved from a log), an event object will be able to provide callback functions for various purposes (such as capability checks).&lt;br /&gt;
; Automatic inclusion&lt;br /&gt;
: Event class definitions will be automatically included when needed, without having to maintain lists of known event types. New event definitions can be added without the need to upgrade, only purging of MUC cache is required after adding new observer.&lt;br /&gt;
; Maintainability&lt;br /&gt;
: It will be easy to add new events and migrate existing events. Code review will be simplified because there will be less duplication of code when triggering events and all event related information/code will be concentrated in one file in fixed locations.&lt;br /&gt;
; Self documenting&lt;br /&gt;
: The behaviour of events will be combined with the definition of events in one place (file). It will be easy for event observer writers to know what events a plugin can trigger. This includes support for autocompletion and code inspection in modern IDEs.&lt;br /&gt;
; Quick, self-validating data structure&lt;br /&gt;
: As events are instantiated objects, the PHP processor will validate the structure and type of event classes. This does not ensure data value validity, but does give some assurance of consistency and it also detects common typos.&lt;br /&gt;
&lt;br /&gt;
== Backwards compatibility and migration ==&lt;br /&gt;
&lt;br /&gt;
Events:&lt;br /&gt;
* Moodle core and standard plugins will replace all calls to the events_trigger() function with new events classes.&lt;br /&gt;
* For events that already exist in Moodle 2.5 the additional legacy information should be added to the event data (in properties &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;.&lt;br /&gt;
* The function events_trigger() will continue working as before, but it will be called automatically after a new event is processed using the &#039;legacyeventname&#039; and &#039;legacyeventdata&#039;.&lt;br /&gt;
* The legacy events handling code will be maintained  separately and will continue being supported in Moodle 2.x. New legacy events will not be added.&lt;br /&gt;
* Existing legacy event handlers will be migrated to new event handlers accepting new event class instances.&lt;br /&gt;
* More subsystems may be migrated to events-handlers, ex.: gradebook history.&lt;br /&gt;
&lt;br /&gt;
Logging:&lt;br /&gt;
* Function add_to_log() and all logging internals will continue working as before.&lt;br /&gt;
* Existing add_to_log() parameters will be migrated inside new events method get_legacy_log_data() and core_event_base::trigger() will call add_to_log() automatically (this will depend on $CFG-&amp;gt;loglifetime setting for performance reasons).&lt;br /&gt;
&lt;br /&gt;
== Event dispatching and observers ==&lt;br /&gt;
&lt;br /&gt;
The new event dispatching system is completely separate from the old events code. Original event handlers are now called observers with the description stored in the same db/events.php file, but as a new array with a different format.&lt;br /&gt;
&lt;br /&gt;
=== Event observers ===&lt;br /&gt;
&lt;br /&gt;
The observers are described in db/events.php in the array $observers, the array is not indexed and contains a list of observers defined as an array with the following properties;&lt;br /&gt;
* eventname - event class name or &amp;quot;*&amp;quot; indicating all events. All events must use namespace, ex.: &#039;&#039;\plugintype_pluginname\event\something_happened&#039;&#039;.&lt;br /&gt;
* callback - PHP callable type.&lt;br /&gt;
* includefile - optional. File to be included before calling the observer. Path relative to dirroot.&lt;br /&gt;
* priority - optional. Defaults to 0. Observers with higher priority are notified first.&lt;br /&gt;
* internal - optional. Defaults to true. Non-internal observers are not called during database transactions, but instead after a successful commit of the transaction.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$observers = array(&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_one&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;\core\event\sample_executed&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::external_observer&#039;,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 200,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; false,&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;eventname&#039;   =&amp;gt; &#039;*&#039;,&lt;br /&gt;
        &#039;callback&#039;    =&amp;gt; &#039;core_event_sample_observer::observe_all&#039;,&lt;br /&gt;
        &#039;includefile&#039; =&amp;gt; null,&lt;br /&gt;
        &#039;internal&#039;    =&amp;gt; true,&lt;br /&gt;
        &#039;priority&#039;    =&amp;gt; 9999,&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;
=== Event dispatching ===&lt;br /&gt;
&lt;br /&gt;
A list of available observers is constructed on the fly directly from all available events.php files. Previously handlers were installed only during installation and upgrade. There is no risk of performance regression because the list is already cached in MUC. Observers get events before installation or any upgrade, however observers are not notified during the initial installation of moodle core tables.&lt;br /&gt;
&lt;br /&gt;
Developers of observers must make sure that execution does not end with a fatal error under any condition (before install, before upgrade or normal operation). Exceptions are automatically captured, logged in the PHP error log, and notification of other observers continues. Current handlers must not throw any exceptions at any time.&lt;br /&gt;
&lt;br /&gt;
Observers are notified sequentially in the same order in which events were triggered. This means that events triggered in observers are queued in FIFO buffer and are processed after all observers are notified.&lt;br /&gt;
&lt;br /&gt;
=== Differences from old event handling ===&lt;br /&gt;
&lt;br /&gt;
# New events contain a lot more structured information.&lt;br /&gt;
# New event data must not contain any PHP classes.&lt;br /&gt;
# There is separate context cache which may be used when deleting data or for observer performance improvements.&lt;br /&gt;
# No database access in new event dispatching code.&lt;br /&gt;
# There is no support for cron execution - this eliminates performance problems, simplifies events dispatching and prevents abuse of cron events.&lt;br /&gt;
# Events triggered in observers are processed in a different order.&lt;br /&gt;
# External events are buffered when a transaction is in progress, instead of being sent to the cron queue.&lt;br /&gt;
# It is possible to define multiple observers for one event in one events.php file.&lt;br /&gt;
# It is possible to subscribe an observer to all events.&lt;br /&gt;
# The new event manager is using frankenstyle autoloading - smaller memory footprint when events are not used on the current page.&lt;br /&gt;
&lt;br /&gt;
== Triggering events ==&lt;br /&gt;
&lt;br /&gt;
* All event descriptions are objects extending the \core\event\base class.&lt;br /&gt;
* Events are triggered by creating a new instance of the class event and executing $event-&amp;gt;trigger().&lt;br /&gt;
* Each event class name is a unique identifier of the event.&lt;br /&gt;
* Class names and namespace follow the identifier scheme \&#039;&#039;&#039;frankenstyle_component&#039;&#039;&#039;\event\&#039;&#039;&#039;some_object_action&#039;&#039;&#039;. Core events have prefix &#039;core_&#039;.&lt;br /&gt;
* Plugins define each event class in a separate file. File name and location must match the class name, for example: &#039;&#039;&#039;plugindir&#039;&#039;&#039;/classes/event/&#039;&#039;&#039;something_happened&#039;&#039;&#039;.php&lt;br /&gt;
* The event identifier suffix has the form &#039;&#039;some_object_action&#039;&#039;  (&#039;&#039;&#039;something_happened&#039;&#039;&#039; in the example above) and should follow our standard naming convention. The last word after underscore is automatically parsed as action, the rest of words is object.&lt;br /&gt;
&lt;br /&gt;
Decision:[[#Verb_list| Recommended verb list]]&lt;br /&gt;
&lt;br /&gt;
Examples: \core\event\course_completed, \mod_assign\event\submission_commented, \mod_forum\event\post_shared, \mod_forum\event\post_responded, etc.&lt;br /&gt;
&lt;br /&gt;
* Ideally, it should be possible to trigger an event without gathering additional information for the event. To reduce the cost of data gathering, specifically the cost of database reads, at least the minimal values needed to trigger an event should be already available in variables.&lt;br /&gt;
&lt;br /&gt;
An example of triggering an event:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \mod_myplugin\event\something_happened::create(array(&#039;context&#039; =&amp;gt; $context, &#039;objectid&#039; =&amp;gt; YYY, &#039;other&#039; =&amp;gt; ZZZ));&lt;br /&gt;
// ... code that may add some record snapshots&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Use of php autoloading ===&lt;br /&gt;
&lt;br /&gt;
All new OOP APIs in Moodle 2.6 are going to use class auto loading - see [[Automatic class loading]]. New events use PHP strictly defined namespaces which concentrate all events classes in classes/event/ subdirectory.&lt;br /&gt;
&lt;br /&gt;
=== Why separate classes? ===&lt;br /&gt;
There were two alternatives proposed on how to define the event structure. The first is a separate class for each event (extending the base class), the other being each event is based on a generic event instance of the base class.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Decision: Use separate class for each event.&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Each plugin creates its own event class for each event&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pros&lt;br /&gt;
* Maintainability - It is much easier to review, debug, integrate.&lt;br /&gt;
* Self documenting, behaviour is combined with definition.&lt;br /&gt;
* It is extremely flexible for plugin developers and core devs too.&lt;br /&gt;
* Automatically lists events without being installed - PHPDocs as events documentation.&lt;br /&gt;
* It is included only when needed using autoloading.&lt;br /&gt;
* Self-validating data structure (by PHP).&lt;br /&gt;
* Some developers will find it easier to copy whole class files as templates.&lt;br /&gt;
Cons&lt;br /&gt;
* Big learning curve for developers without OOP skills (all other new subsystems in Moodle already use OOP, you can not code without these skills any more).&lt;br /&gt;
* Some developers may find it harder to copy-and-paste examples because they will need to create new class first and use it afterwards (this can be viewed as a benefit because it forces developers to think more about events).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Each plugin defines events in a list based on a generic object&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Pros&lt;br /&gt;
* Easier for some developers (this can be eliminated with developer documentation).&lt;br /&gt;
* Some developers think it gives more control of event structure in core (we can easily solve that with private access and validation in the base class).&lt;br /&gt;
Cons&lt;br /&gt;
* It is not flexible enough. PHP code gives developers more freedom.&lt;br /&gt;
* It would not be possible to implement any performance hacks in custom methods. All data would have to be calculated even if it is not used.&lt;br /&gt;
* It would be necessary to define access control callbacks in other code.&lt;br /&gt;
* It would be harder and slower to integrate legacy logging.&lt;br /&gt;
* It would be harder and slower to implement support for legacy events.&lt;br /&gt;
* Event observers could not use event class names as reliable identifiers.&lt;br /&gt;
* Event object and action could not be parsed from class name, it would have to be stored in event properties every time you trigger event.&lt;br /&gt;
* Requires upgrade/install to register an event in DB table with MUC cache. Events could not be triggered earlier.&lt;br /&gt;
* The localised descriptions and names would have to be stored as properties, it would not be possible to store them in any definition.&lt;br /&gt;
* The implementation of an events infrastructure would be significantly more complex and error prone.&lt;br /&gt;
&lt;br /&gt;
== Information contained in events ==&lt;br /&gt;
&lt;br /&gt;
Events have to contain as much information as they can, but this should not affect the performance. That&#039;s why part of the information is available in properties, and the rest via methods. This allows for delaying the computation of the data at the time it is really needed, if it ever is.&lt;br /&gt;
&lt;br /&gt;
=== Properties ===&lt;br /&gt;
&lt;br /&gt;
List of properties that the developer has to pass to the event upon creation, or automatically generated when possible and cost free. Some of those properties not mandatory.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property name&lt;br /&gt;
! Title&lt;br /&gt;
! Type&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;eventname&#039;&#039;&lt;br /&gt;
| Event name&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| Automatically computed by copying class name&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;component&#039;&#039;&lt;br /&gt;
| Component&lt;br /&gt;
| &#039;&#039;static, automatic from top namespace&#039;&#039;&lt;br /&gt;
| Component declaring the event, automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;action&#039;&#039;&lt;br /&gt;
| Action&lt;br /&gt;
| &#039;&#039;static, automatic from last word in class name&#039;&#039;&lt;br /&gt;
| Can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;target&#039;&#039;&lt;br /&gt;
| target of action&lt;br /&gt;
| &#039;&#039;static, automatic from class name&#039;&#039;&lt;br /&gt;
| Target on which the action is taken, can be automatically computed from class name.&lt;br /&gt;
|-&lt;br /&gt;
| objecttable&lt;br /&gt;
| Database table name&lt;br /&gt;
|&lt;br /&gt;
| optional database table name where is/was the object stored. Never use a relationship table here.&lt;br /&gt;
|-&lt;br /&gt;
| objectid&lt;br /&gt;
| Object ID&lt;br /&gt;
|&lt;br /&gt;
| optional id of the object record from objecttable&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;crud&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Transaction type&lt;br /&gt;
| &#039;&#039;static mandatory&#039;&#039;&lt;br /&gt;
| One of [crud] letters. Statically declared in the event class method init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;&#039;&#039;level&#039;&#039;&#039;&#039;&#039;&lt;br /&gt;
| Level&lt;br /&gt;
| &#039;&#039;static mandatory&#039;&#039;&lt;br /&gt;
| Level of educational value of the event. Statically declared in the event class method init(). (See below for more details)&lt;br /&gt;
|-&lt;br /&gt;
| contextid&lt;br /&gt;
| Context ID&lt;br /&gt;
| mandatory&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| contextlevel&lt;br /&gt;
| Context level&lt;br /&gt;
| automatic from context&lt;br /&gt;
| This tells you if it was a course, activity, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| contextinstanceid&lt;br /&gt;
| Context instanceid&lt;br /&gt;
| automatic from context&lt;br /&gt;
| Based on context level this may be course id , course module id, course category, etc.&lt;br /&gt;
|-&lt;br /&gt;
| userid&lt;br /&gt;
| User ID&lt;br /&gt;
| defaults to current user&lt;br /&gt;
| User ID, or 0 when not logged in, or -1 when other (System, CLI, Cron, ...)&lt;br /&gt;
|-&lt;br /&gt;
| courseid&lt;br /&gt;
| Affected course&lt;br /&gt;
| defaults to course context from context&lt;br /&gt;
| This is used only for contexts at and bellow course level - this can be used to filter events by course (includes all course activities)&lt;br /&gt;
|-&lt;br /&gt;
| relateduserid&lt;br /&gt;
| Affected user&lt;br /&gt;
|&lt;br /&gt;
| Is this action related to some user? This could be used for some personal timeline view.&lt;br /&gt;
|-&lt;br /&gt;
| other&lt;br /&gt;
| All other data&lt;br /&gt;
|&lt;br /&gt;
| Any other fields needed for event description - scalars or arrays, must be serialisable using json_encode()&lt;br /&gt;
|-&lt;br /&gt;
| timecreated&lt;br /&gt;
| Time of the event&lt;br /&gt;
| automatic&lt;br /&gt;
|&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;static&#039;&#039;: It is the same for all event instances of this class.&lt;br /&gt;
* &#039;&#039;&#039;mandatory&#039;&#039;&#039;: Is required in order to trigger the event.&lt;br /&gt;
&lt;br /&gt;
==== Level property ====&lt;br /&gt;
&lt;br /&gt;
The level property helps defining the educational value of the event. It is intentional that the list is limited to only 3 different constants, having too many options would make it harder for developers to pick the right one(s). We also have to keep in mind that this is not supposed to answer all the questions about a particular event, other event properties like the courseid, the context, the component name can be used with the level to get more granular reports.&lt;br /&gt;
&lt;br /&gt;
Remember that this is event based. If the user that has triggered the event is not really &amp;quot;participating&amp;quot; because he is an admin, or a manager, then it is the job of the report to filter those. The event itself has a static educational level.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Teaching&#039;&#039;&#039; (LEVEL_TEACHING: 1)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by someone (typically a teacher) and has a teaching value (anything that is affecting the learning experience/environment of the students). This should not be combined with &amp;quot;Participating&amp;quot; events.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A teacher grading a student&lt;br /&gt;
* A teacher modifying the course settings&lt;br /&gt;
* A teacher adding a new section to the course page&lt;br /&gt;
* A teacher modifying a module settings&lt;br /&gt;
* A teacher adding a page to course&lt;br /&gt;
* A teacher leaving a feedback&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A teacher posting in a forum (it might affect the learning experience, but not necessarily, so the teacher is just participating)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Participating&#039;&#039;&#039; (LEVEL_PARTICIPATING: 2)&lt;br /&gt;
&lt;br /&gt;
Any event/action that is performed by a user, that is related (or could be related) to his learning experience.&lt;br /&gt;
&lt;br /&gt;
Valid events:&lt;br /&gt;
&lt;br /&gt;
* A user posting to a forum&lt;br /&gt;
* A user submitting an assignment&lt;br /&gt;
* A user blogging&lt;br /&gt;
* A user reading someone&#039;s blog&lt;br /&gt;
* A user posting a comment&lt;br /&gt;
* A user chatting on a chat activity&lt;br /&gt;
* A user viewing the course page&lt;br /&gt;
* A user deletes a blog post&lt;br /&gt;
&lt;br /&gt;
INVALID events:&lt;br /&gt;
&lt;br /&gt;
* A user updating his profile&lt;br /&gt;
* A user visiting someone&#039;s profile&lt;br /&gt;
* A user viewing his /my/ page&lt;br /&gt;
* A user sending a message to another one&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Other&#039;&#039;&#039; (LEVEL_OTHER: 0)&lt;br /&gt;
&lt;br /&gt;
Any other action, whether they are related to the site administration, or are specific to user. They do not have any educational value.&lt;br /&gt;
&lt;br /&gt;
=== Methods ===&lt;br /&gt;
&lt;br /&gt;
The computation of this data is not required by default, but can be accessed by any event observer if need be.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| get_name()&lt;br /&gt;
| Returns localised name of the event, it is the same for all instances.&lt;br /&gt;
|-&lt;br /&gt;
| get_description()&lt;br /&gt;
| Returns localised description of one particular event.&lt;br /&gt;
|-&lt;br /&gt;
| can_view($user)&lt;br /&gt;
| Can the specified user view the event?&lt;br /&gt;
|-&lt;br /&gt;
| get_url()&lt;br /&gt;
| Returns Moodle URL where the event can be observed afterwards.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventname()&lt;br /&gt;
| Information necessary for event BC.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_eventdata()&lt;br /&gt;
| Information necessary for event BC.&lt;br /&gt;
|-&lt;br /&gt;
| get_legacy_logdata()&lt;br /&gt;
| Information necessary for logging BC.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
===Record caching===&lt;br /&gt;
&lt;br /&gt;
The standard event data may not contain all the information observers need. The built-in record snapshot support in events allows developers to attach more auxiliary information when triggering events, it may be for example course record, some record that was just deleted, etc. The snapshot is meant to be a full database record, as it will be automatically fetched from get_record_snapshot() if not set previously and assuming the property &#039;&#039;objecttable&#039;&#039; is set. Please be aware that the snapshots are not stored in the event, and cannot be restored.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_assigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    $event = \core\event\role_unassigned::create(&lt;br /&gt;
        array(&#039;context&#039;=&amp;gt;$context, &#039;objectid&#039;=&amp;gt;$ra-&amp;gt;roleid, &#039;relateduserid&#039;=&amp;gt;$ra-&amp;gt;userid,&lt;br /&gt;
            &#039;other&#039;=&amp;gt;array(&#039;id&#039;=&amp;gt;$ra-&amp;gt;id, &#039;component&#039;=&amp;gt;$ra-&amp;gt;component, &#039;itemid&#039;=&amp;gt;$ra-&amp;gt;itemid)));&lt;br /&gt;
    $event-&amp;gt;add_record_snapshot(&#039;role_assignments&#039;, $ra);&lt;br /&gt;
    $event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The related methods are:&lt;br /&gt;
* public function add_record_snapshot($tablename, $record)&lt;br /&gt;
* public function get_record_snapshot($tablename, $id)&lt;br /&gt;
&lt;br /&gt;
=== Rejected properties and methods ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Property&lt;br /&gt;
! Title&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| URL&lt;br /&gt;
| relevant page URL&lt;br /&gt;
| These URLs can be constructed on the fly from other data, external log plugins may use get_url() method.&lt;br /&gt;
|-&lt;br /&gt;
| version&lt;br /&gt;
| Event specification number&lt;br /&gt;
| The event specification should never change&lt;br /&gt;
|-&lt;br /&gt;
| type&lt;br /&gt;
| Type of event (action, error, ...)&lt;br /&gt;
| Event are not intended for error logging or debugging.&lt;br /&gt;
|-&lt;br /&gt;
| actor&lt;br /&gt;
| Whether current execution is cron, cli, user, ...&lt;br /&gt;
| Impossible to track down at a low level&lt;br /&gt;
|-&lt;br /&gt;
| severity&lt;br /&gt;
| Severity following [http://tools.ietf.org/html/rfc5424#section-6.2.1 logging standards]&lt;br /&gt;
| Our logging does not match this, as we will not (at present) log errors&lt;br /&gt;
|-&lt;br /&gt;
| coursecatname&lt;br /&gt;
| Category name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| coursename&lt;br /&gt;
| Course name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| cmname&lt;br /&gt;
| Course module name&lt;br /&gt;
| Might be costly to retrieve for little gain&lt;br /&gt;
|-&lt;br /&gt;
| categoryid &lt;br /&gt;
| Course category id&lt;br /&gt;
| Categories are a tree structure, we can not identify them by one integer. It would have to be a path.&lt;br /&gt;
|-&lt;br /&gt;
| cmid &lt;br /&gt;
| Course module id&lt;br /&gt;
| Can be derived from contextlevel and contextinstanceid&lt;br /&gt;
|-&lt;br /&gt;
| associatedobject&lt;br /&gt;
| Associated object&lt;br /&gt;
| Object associated to the main object. Ie: The user to whom a message is sent.&lt;br /&gt;
|-&lt;br /&gt;
| associatedobjectid&lt;br /&gt;
| Associated object ID&lt;br /&gt;
| Identifier of the associated object&lt;br /&gt;
|-&lt;br /&gt;
| realuserid&lt;br /&gt;
| Real User ID&lt;br /&gt;
| Will be tracked by log plugins only - user who &amp;quot;logged in as&amp;quot;, stores the real user ID&lt;br /&gt;
|-&lt;br /&gt;
| origin&lt;br /&gt;
| Origin of the event&lt;br /&gt;
| Will be tracked by log plugins only - CLI, cron, Webservice, ... (optionally with IP address)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Method&lt;br /&gt;
! Comment&lt;br /&gt;
! Why&lt;br /&gt;
|-&lt;br /&gt;
| get_all_affected_users()&lt;br /&gt;
| Returns all the users affected by this event&lt;br /&gt;
| It is expensive to fetch all users and it changes in time, so it would be unreliable too. For now we store only one user who is related to each event.&lt;br /&gt;
|-&lt;br /&gt;
| get_objecturl()&lt;br /&gt;
| Returns the URL to view the object&lt;br /&gt;
| There is usually only one URL where event changes may be observed. The URL may depend on current user capabilities too.&lt;br /&gt;
|-&lt;br /&gt;
| get_associatedobjecturl()&lt;br /&gt;
| Returns the URL to view the associated object&lt;br /&gt;
| No associated user property is present.&lt;br /&gt;
|-&lt;br /&gt;
| get_currenturl()&lt;br /&gt;
| Returns the current URL, uses $PAGE.&lt;br /&gt;
| This information may be added by logger, current page info is not part of events data.&lt;br /&gt;
|-&lt;br /&gt;
| get_useripaddress()&lt;br /&gt;
| Returns the User IP address&lt;br /&gt;
| Page access method is not part of events API, this should be implemented as logdata properties in loggers.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Events naming convention ==&lt;br /&gt;
&lt;br /&gt;
Clear event names help developers when reading what events are triggered, and defining the events properties when defining the event class.&lt;br /&gt;
&lt;br /&gt;
 Decision: \&amp;lt;component&amp;gt;\event\&amp;lt;some_object&amp;gt;_&amp;lt;verb&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Structure of existing events ===&lt;br /&gt;
&lt;br /&gt;
List of existing events called in 2.5, along with their future name and the decomposition of the new name into &#039;&#039;action&#039;&#039; and &#039;&#039;object&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! 2.5 name&lt;br /&gt;
! New name&lt;br /&gt;
! Subject&lt;br /&gt;
! Action&lt;br /&gt;
! Object&lt;br /&gt;
! &amp;lt;relationship&amp;gt;&lt;br /&gt;
! Object 2&lt;br /&gt;
! Comment&lt;br /&gt;
|-&lt;br /&gt;
| activity_completion_changed&lt;br /&gt;
| &#039;&#039;&#039;core_event_activity_completion_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| changed&lt;br /&gt;
| completion&lt;br /&gt;
| of&lt;br /&gt;
| activity&lt;br /&gt;
|-&lt;br /&gt;
| assessable_content_uploaded&lt;br /&gt;
| &#039;&#039;&#039;mod_*_event_assessablecontent_uploaded&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| uploaded&lt;br /&gt;
| assessablecontent&lt;br /&gt;
|-&lt;br /&gt;
| assessable_files_done&lt;br /&gt;
| &#039;&#039;&#039;mod_*_event_assessablecontent_processed&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| processed&lt;br /&gt;
| assessable content&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| assessable_file_uploaded&lt;br /&gt;
|&lt;br /&gt;
| Someone&lt;br /&gt;
| uploaded&lt;br /&gt;
| assessable_file&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;To be deprecated MDL-35197&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| assessable_submitted&lt;br /&gt;
| &#039;&#039;&#039;mod_*_event_assessablecontent_submitted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| submitted&lt;br /&gt;
| assessable content&lt;br /&gt;
|- &lt;br /&gt;
| blog_entry_added&lt;br /&gt;
| &#039;&#039;&#039;mod_blog_event_entry_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| added&lt;br /&gt;
| entry&lt;br /&gt;
|-&lt;br /&gt;
| blog_entry_deleted&lt;br /&gt;
| &#039;&#039;&#039;mod_blog_event_entry_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| entry&lt;br /&gt;
|-&lt;br /&gt;
| blog_entry_edited&lt;br /&gt;
| &#039;&#039;&#039;mod_blog_event_entry_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| updated&lt;br /&gt;
| entry&lt;br /&gt;
|-&lt;br /&gt;
| cohort_added&lt;br /&gt;
| &#039;&#039;&#039;core_event_cohort_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| created&lt;br /&gt;
| cohort&lt;br /&gt;
|-&lt;br /&gt;
| cohort_deleted&lt;br /&gt;
| &#039;&#039;&#039;core_event_cohort_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| cohort&lt;br /&gt;
|-&lt;br /&gt;
| cohort_updated&lt;br /&gt;
| &#039;&#039;&#039;core_event_cohort_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| updated&lt;br /&gt;
| cohort&lt;br /&gt;
|-&lt;br /&gt;
| cohort_member_added&lt;br /&gt;
| &#039;&#039;&#039;core_event_cohort_member_added&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| added&lt;br /&gt;
| member&lt;br /&gt;
| to&lt;br /&gt;
| cohort&lt;br /&gt;
|-&lt;br /&gt;
| cohort_member_removed&lt;br /&gt;
| &#039;&#039;&#039;core_event_cohort_member_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| member&lt;br /&gt;
| from&lt;br /&gt;
| cohort&lt;br /&gt;
|-&lt;br /&gt;
| course_category_deleted&lt;br /&gt;
| &#039;&#039;&#039;core_event_coursecat_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| coursecat&lt;br /&gt;
|-&lt;br /&gt;
| course_completed&lt;br /&gt;
| &#039;&#039;&#039;core_event_course_completed&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| completed&lt;br /&gt;
| course&lt;br /&gt;
|-&lt;br /&gt;
| course_content_removed&lt;br /&gt;
| &#039;&#039;&#039;core_event_course_purged&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| purged&lt;br /&gt;
| course&lt;br /&gt;
|-&lt;br /&gt;
| course_created&lt;br /&gt;
| &#039;&#039;&#039;core_event_course_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| created&lt;br /&gt;
| course&lt;br /&gt;
|-&lt;br /&gt;
| course_deleted&lt;br /&gt;
| &#039;&#039;&#039;core_event_course_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| course&lt;br /&gt;
|-&lt;br /&gt;
| course_restored&lt;br /&gt;
| &#039;&#039;&#039;core_event_course_restored&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| restored&lt;br /&gt;
| course&lt;br /&gt;
|-&lt;br /&gt;
| course_updated&lt;br /&gt;
| &#039;&#039;&#039;core_event_course_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| updated&lt;br /&gt;
| course&lt;br /&gt;
|-&lt;br /&gt;
| groups_group_created&lt;br /&gt;
| &#039;&#039;&#039;core_event_group_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| created&lt;br /&gt;
| group&lt;br /&gt;
|-&lt;br /&gt;
| groups_group_deleted&lt;br /&gt;
| &#039;&#039;&#039;core_event_group_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| group&lt;br /&gt;
|-&lt;br /&gt;
| groups_grouping_created&lt;br /&gt;
| &#039;&#039;&#039;core_event_grouping_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| created&lt;br /&gt;
| grouping&lt;br /&gt;
|-&lt;br /&gt;
| groups_grouping_deleted&lt;br /&gt;
| &#039;&#039;&#039;core_event_grouping_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| grouping&lt;br /&gt;
|-&lt;br /&gt;
| groups_groupings_deleted&lt;br /&gt;
|&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| groupings&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;To deprecate&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| groups_groupings_groups_removed&lt;br /&gt;
|&lt;br /&gt;
| Someone&lt;br /&gt;
| removed&lt;br /&gt;
| groups&lt;br /&gt;
| from&lt;br /&gt;
| groupings&lt;br /&gt;
| &#039;&#039;To deprecate&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| groups_grouping_updated&lt;br /&gt;
| &#039;&#039;&#039;core_event_grouping_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| updated&lt;br /&gt;
| grouping&lt;br /&gt;
|-&lt;br /&gt;
| groups_groups_deleted&lt;br /&gt;
| &lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| groups&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;To deprecate&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| groups_group_updated&lt;br /&gt;
| &#039;&#039;&#039;core_event_group_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| updated&lt;br /&gt;
| group&lt;br /&gt;
|-&lt;br /&gt;
| groups_member_added&lt;br /&gt;
| &#039;&#039;&#039;core_event_group_member_added&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| added&lt;br /&gt;
| member&lt;br /&gt;
| to&lt;br /&gt;
| group&lt;br /&gt;
|-&lt;br /&gt;
| groups_member_removed&lt;br /&gt;
| &#039;&#039;&#039;core_event_group_member_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| member&lt;br /&gt;
| from&lt;br /&gt;
| group&lt;br /&gt;
|-&lt;br /&gt;
| groups_members_removed&lt;br /&gt;
|&lt;br /&gt;
| Someone&lt;br /&gt;
| removed&lt;br /&gt;
| members&lt;br /&gt;
| from&lt;br /&gt;
| group&lt;br /&gt;
| &#039;&#039;To deprecate&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| lti_unknown_service_api_call&lt;br /&gt;
| &#039;&#039;&#039;mod_lti_event_unknownservice_called&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| called&lt;br /&gt;
| unknown service&lt;br /&gt;
|-&lt;br /&gt;
| mod_created&lt;br /&gt;
| &#039;&#039;&#039;core_event_module_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| created&lt;br /&gt;
| module&lt;br /&gt;
|-&lt;br /&gt;
| mod_deleted&lt;br /&gt;
| &#039;&#039;&#039;core_event_module_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| module&lt;br /&gt;
|-&lt;br /&gt;
| portfolio_send&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
| &#039;&#039;This is a hack...&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| role_assigned&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_role_added&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| added&lt;br /&gt;
| role&lt;br /&gt;
| to&lt;br /&gt;
| user&lt;br /&gt;
| &#039;&#039;Or ..._role_assigned&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| role_unassigned&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_role_removed&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| removed&lt;br /&gt;
| role&lt;br /&gt;
| from&lt;br /&gt;
| user&lt;br /&gt;
| &#039;&#039;Or ..._role_unassigned&#039;&#039;&lt;br /&gt;
|-&lt;br /&gt;
| quiz_attempt_started&lt;br /&gt;
| &#039;&#039;&#039;mod_quiz_event_attempt_started&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| started&lt;br /&gt;
| attempt&lt;br /&gt;
| of&lt;br /&gt;
| quiz&lt;br /&gt;
|-&lt;br /&gt;
| test_cron&lt;br /&gt;
|-&lt;br /&gt;
| test_instant&lt;br /&gt;
|-&lt;br /&gt;
| user_created&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| created&lt;br /&gt;
| user&lt;br /&gt;
|-&lt;br /&gt;
| user_deleted&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| deleted&lt;br /&gt;
| user&lt;br /&gt;
|-&lt;br /&gt;
| user_enrolled&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_enrolment_created&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| added&lt;br /&gt;
| enrolment&lt;br /&gt;
| of&lt;br /&gt;
| user&lt;br /&gt;
|-&lt;br /&gt;
| user_enrol_modified&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_enrolment_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| updated&lt;br /&gt;
| enrolment&lt;br /&gt;
| of&lt;br /&gt;
| user&lt;br /&gt;
|-&lt;br /&gt;
| user_unenrolled&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_enrolment_deleted&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| removed&lt;br /&gt;
| enrolment&lt;br /&gt;
| of&lt;br /&gt;
| user&lt;br /&gt;
|-&lt;br /&gt;
| user_logout&lt;br /&gt;
| &#039;&#039;&#039;core_event_loggedout&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| loggedout&lt;br /&gt;
|-&lt;br /&gt;
| user_updated&lt;br /&gt;
| &#039;&#039;&#039;core_event_user_updated&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| updated&lt;br /&gt;
| user&lt;br /&gt;
|-&lt;br /&gt;
| workshop_viewed&lt;br /&gt;
| &#039;&#039;&#039;mod_workshop_event_viewed&#039;&#039;&#039;&lt;br /&gt;
| Someone&lt;br /&gt;
| viewed&lt;br /&gt;
| workshop&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Verb list ===&lt;br /&gt;
All events must use a verb from this list. New verbs should be added to this list if required.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!verb&lt;br /&gt;
!Explanation&lt;br /&gt;
!Source&lt;br /&gt;
|-&lt;br /&gt;
|accepted&lt;br /&gt;
|Example: Accepting a statement when submitting an assignment.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|added&lt;br /&gt;
|	Used to represent &amp;quot;something that already exists is now part of/bound to another entity&amp;quot;. Examples: &amp;quot;Admin added role to user X&amp;quot;, &amp;quot;Admin added user X to group A&amp;quot;. Wrong example: &amp;quot;User added course in category&amp;quot; because it is a &#039;move&#039; action, except if a course can be part of multiple categories. The good examples work because: A user can have multiple roles, a user can be in multiple groups.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|answered&lt;br /&gt;
| Indicates the actor responded to a Question&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|attempted&lt;br /&gt;
|&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|awarded&lt;br /&gt;
|	ex:-teacher awarded student a badge.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|backedup&lt;br /&gt;
|	When a backup has been performed.&lt;br /&gt;
|Moodle	&lt;br /&gt;
|-&lt;br /&gt;
|called&lt;br /&gt;
|When a call to something is made like an API @see unknown_service_api_called.php&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|commented&lt;br /&gt;
|Offered an opinion or written experience of the activity. Can be used with the learner as the actor or a system as an actor. Comments can be sent from either party with the idea that the other will read and react to the content.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|completed&lt;br /&gt;
|To experience the activity in its entirety. Used to affirm the completion of content. This can be simply experiencing all the content, be tied to objectives or interactions, or determined in any other way. Any content that has been initialized, but not yet completed, should be considered incomplete. There is no verb to &#039;incomplete&#039; an activity, one would void the statement which completes the activity.&amp;quot;&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|created&lt;br /&gt;
|	Used to represent &amp;quot;something new has been created&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|deleted&lt;br /&gt;
|	Used to indicate the object in context was deleted.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|duplicated&lt;br /&gt;
|For something that has been copied.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|failed&lt;br /&gt;
|Learner did not perform the activity to a level of pre-determined satisfaction. Used to affirm the lack of success a learner experienced within the learning content in relation to a threshold. If the user performed below the minimum to the level of this threshold, the content is &#039;failed&#039;. The opposite of &#039;passed&#039;.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|graded&lt;br /&gt;
|Used to represent an activity was graded.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|imported&lt;br /&gt;
|The act of moving an object into another location or system.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|loggedin/loggedout&lt;br /&gt;
|	For login and logout.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|loggedinas&lt;br /&gt;
|	 If user is logged in as different user. This is used by only one event (user_loggedinas). Adding this verb makes event name more clear, then using loggedin verb.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|locked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|moved&lt;br /&gt;
|	Used to indicate the object in context was moved.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|passed&lt;br /&gt;
|Used to affirm the success a learner experienced within the learning content in relation to a threshold. If the user performed at a minimum to the level of this threshold, the content is &#039;passed&#039;. The opposite of &#039;failed&#039;.&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|previewed&lt;br /&gt;
|Something has been previewed.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|submitted&lt;br /&gt;
|This is very close to &amp;quot;Attempted&amp;quot;. Depends on context which one should be used. For example:- &amp;quot;Admin submitted a form. Student attempted a quiz.&amp;quot;  is correct, however some cases might not be as clear as the previous example. We can say both &amp;quot;Student submitted an assignment&amp;quot; or &amp;quot;student attempted an assignment&amp;quot;. We need to make the difference clear.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|suspended&lt;br /&gt;
| Suspend something. (example a user)&lt;br /&gt;
| Tincan (However the context is different)&lt;br /&gt;
|-&lt;br /&gt;
|viewed&lt;br /&gt;
|Something has been viewed. For example:- &amp;quot;Student viewed chapter 1 of book 1.&amp;quot;&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|registered&lt;br /&gt;
|Indicates the actor registered for a learning activity&lt;br /&gt;
|Tincan&lt;br /&gt;
|-&lt;br /&gt;
|removed&lt;br /&gt;
|By opposition to &amp;quot;Added&amp;quot;. This does not mean that the object has been deleted, but removed from the entity, or not bound to it any more.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|restored&lt;br /&gt;
|	When restoring a backup. Rolling back to a previous state.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|reset&lt;br /&gt;
|	Sets one or more properties back to the default value.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|revealed&lt;br /&gt;
|Example: Identities revealed after blind marking.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|unlocked&lt;br /&gt;
|&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|upgraded&lt;br /&gt;
|Something was upgraded, some module probably&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|updated&lt;br /&gt;
|Used to indicate the object in context was updated. Simple example is &amp;quot;Admin updated course xyz&amp;quot;.&lt;br /&gt;
|Moodle&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Rules ===&lt;br /&gt;
&lt;br /&gt;
==== Use singular ====&lt;br /&gt;
&lt;br /&gt;
Plurals must be used on objects when it&#039;s a &#039;&#039;One to Many&#039;&#039; relationship. Ex: bulk import, mass deletion, ... In any other case, use the singular.&lt;br /&gt;
&lt;br /&gt;
==== Ends with a verb ====&lt;br /&gt;
&lt;br /&gt;
The last word (after the last underscore) must be a verb.&lt;br /&gt;
&lt;br /&gt;
== Shared events ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Not supported at this stage.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.5 we have a good example of a shared event: &#039;assessable_content_uploaded&#039; which is triggered in &#039;&#039;forum&#039;&#039;, &#039;assignment&#039;&#039; and &#039;&#039;workshop&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
The problem with shared events is that we cannot easily track what component triggered them. Of course we could add a new property to the event to keep track of that, but we would soon need more information and more properties. Also, in the case of a logger, the event received would be unique, where in fact it should be considered different depending on the component firing it.&lt;br /&gt;
&lt;br /&gt;
In our first implementation, we will create one specific event per module. This flexibility does not prevent any observer from capturing them, but still makes sure that the consistency and specificity of each event is maintained.&lt;br /&gt;
&lt;br /&gt;
It could happen that some events are defined in core and shared, but this should not really happen as low-level APIs should trigger the event, and a module should call that low API instead of doing the job itself.&lt;br /&gt;
&lt;br /&gt;
== One to many ==&lt;br /&gt;
&lt;br /&gt;
 Decision: Each event should have a one to one relationship. We can reconsider this at a later stage, if the performance hit is extremely high.&lt;br /&gt;
&lt;br /&gt;
In 2.5, some events are triggered when an action happens on multiple objects. We have to decide whether we want to keep supporting &#039;&#039;One to Many&#039;&#039; events or not.&lt;br /&gt;
&lt;br /&gt;
Keeping a list of all changes for multiple actions may be problematic because you would have to keep them all in memory until all things are processed. This might also result in the order of events being incorrect. The only correct solution seems to be to trigger each item individually and then many things at the end. Performance needs to be improved elsewhere...&lt;br /&gt;
&lt;br /&gt;
=== Accuracy ===&lt;br /&gt;
&lt;br /&gt;
When uploading a bunch of users using the CSV upload feature, if only one event is triggered, it means that the observers of &#039;&#039;user_created&#039;&#039; won&#039;t be triggered. And so some functionality can be lost as, as a plugin developer, I expect this &#039;&#039;user_created&#039;&#039; to be triggered regardless of the way they have been uploaded. Of course, the developer could observe the event &#039;&#039;bulk_user_imported&#039;&#039;, but that means that he could miss some relevant observers.&lt;br /&gt;
&lt;br /&gt;
This applies to existing events.&lt;br /&gt;
&lt;br /&gt;
=== Performance ===&lt;br /&gt;
&lt;br /&gt;
Triggering one event is cheaper then repeating the same events x number of times...&lt;br /&gt;
&lt;br /&gt;
=== Information tracking ===&lt;br /&gt;
&lt;br /&gt;
A &#039;&#039;bulk&#039;&#039; event, might not be verbose enough to allow for proper logging afterwards. Though this is the responsibility of the logger, we probably want to make it easy to store relevant information.&lt;br /&gt;
&lt;br /&gt;
=== Double event ===&lt;br /&gt;
&lt;br /&gt;
In the case of a bulk user import, if we were to trigger an event per user created, we probably want to trigger one event &#039;user_bulk_upload_started&#039; when the action starts.&lt;br /&gt;
&lt;br /&gt;
== Unit Testing ==&lt;br /&gt;
&lt;br /&gt;
With unit testing for this system we want to assert the following:&lt;br /&gt;
&lt;br /&gt;
* That event strict validation and custom validation works.&lt;br /&gt;
* Missing event data is auto filled with accurate data.&lt;br /&gt;
* Typos in properties passed to ::create() are captured (if we decide to validate).&lt;br /&gt;
* The legacy methods return the expected values.&lt;br /&gt;
* The class properties are correctly overridden (crud, level, action, object, ...).&lt;br /&gt;
* The properties automatically generated (component, name, ...) are correct.&lt;br /&gt;
* Events are dispatched to the corresponding observers.&lt;br /&gt;
* Events are dispatched to the corresponding legacy handlers.&lt;br /&gt;
* Events are dispatched to the * observers.&lt;br /&gt;
* Events perform an add_to_log() if it has legacy log data.&lt;br /&gt;
* &#039;Events restore&#039; restored the whole event data, and does not miss any information.&lt;br /&gt;
* &#039;Events restore&#039; does not generate any extra information.&lt;br /&gt;
&lt;br /&gt;
= Example events =&lt;br /&gt;
&lt;br /&gt;
== Assignment ==&lt;br /&gt;
&lt;br /&gt;
Assumption: Course contains groups with students in each group.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1.&#039;&#039;&#039; Teacher creates an assignment with group mode set to &#039;Separate groups&#039; and Feedback type set to comments and files.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has created assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;2.&#039;&#039;&#039; A student views the assignment.&lt;br /&gt;
*Event: User &#039;Student&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;3.&#039;&#039;&#039; A member from one of the groups submits an assignment&lt;br /&gt;
*Event: User &#039;Student&#039; has added a submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;4.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to the teacher and all students in that group.&lt;br /&gt;
&#039;&#039;&#039;5.&#039;&#039;&#039; Teacher views the assignment.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;6.&#039;&#039;&#039; Teacher clicks on &#039;View/grade all submissions&#039;&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the assignment &#039;B&#039; grade area in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;7.&#039;&#039;&#039; Teacher clicks to grade the student&#039;s submission.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;8.&#039;&#039;&#039; Teacher marks the assignment with the setting &#039;Apply grades and feedback to entire group&#039; set to &#039;Yes&#039; leaving a comment and a file.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a file to the course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been marked. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;9.&#039;&#039;&#039; User &#039;Adrian&#039; views the feedback.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;10.&#039;&#039;&#039; User &#039;Adrian&#039; opens the feedback file.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has viewed the file &#039;A&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;11.&#039;&#039;&#039; User &#039;Adrian&#039; adds some changes to the assignment insulting the teachers marking and updates it.&lt;br /&gt;
*Event: User &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039; for group &#039;C&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Teacher&#039; notifying them that user &#039;Adrian&#039; has updated the submission for assignment &#039;B&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Student&#039; notifying them their submission for assignment &#039;B&#039; has been updated. - This is done for all users in the group.&lt;br /&gt;
&#039;&#039;&#039;12.&#039;&#039;&#039; The teacher clicks directly on the link in the email to be taken to the grading page.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has viewed the submission for user &#039;student&#039; for assignment &#039;B&#039; in course &#039;C101&#039;.&lt;br /&gt;
&#039;&#039;&#039;13.&#039;&#039;&#039; The teacher is upset due to the harsh comments and decides to mark Adrian down, but not the rest of the group by setting &#039;Apply grades and feedback to entire group&#039; set to &#039;No&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has marked assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has left a comment for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: User &#039;Teacher&#039; has uploaded a feedback file for assignment &#039;B&#039; for user &#039;Adrian&#039; in course &#039;C101&#039;.&lt;br /&gt;
*Event: Email sent to user &#039;Adrian&#039; notifying them their submission for assignment &#039;B&#039; has been marked.&lt;br /&gt;
&lt;br /&gt;
= FAQs =&lt;br /&gt;
&lt;br /&gt;
; Why not use create events in core subsystems? : Because we could not see all core events in one place, it would create problems when naming event classes and finally subsystems are incomplete, we would have to add more now because we could not move the events in the future.&lt;br /&gt;
&lt;br /&gt;
= Development stages =&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
&lt;br /&gt;
* Finish class loader spec and implement basic Frankenstyle class loader.&lt;br /&gt;
* Describe new observer definition - just few new flags in current db/events.php&lt;br /&gt;
* Describe new event dispatcher.&lt;br /&gt;
* Describe core_event_base class.&lt;br /&gt;
* Current (= legacy) events triggering:&lt;br /&gt;
** Re-factor current event handling code to new self-contained class - do not change functionality, keep events_trigger().&lt;br /&gt;
** Create new event handler management class that deals with installation and upgrades of both legacy and new handlers.&lt;br /&gt;
* New events:&lt;br /&gt;
** Create new core_event_base class.&lt;br /&gt;
** Create new self-contained event dispatcher class with &#039;*&#039; handler support.&lt;br /&gt;
** In function core_event_base::trigger() check if the  event has property &#039;legacyeventname&#039; execute events_trigger($this-&amp;gt;legacyeventname, $this-&amp;gt;legacyeventdata) after triggering new event.&lt;br /&gt;
** Write unit tests for all new events code.&lt;br /&gt;
* No changes to be made to the current logging system yet.&lt;br /&gt;
&lt;br /&gt;
After completing this stage everything should continue to work as it did before and we can start parallel work on further stages.&lt;br /&gt;
&lt;br /&gt;
== Stage 2 (requires completion of Stage 1) ==&lt;br /&gt;
&lt;br /&gt;
* Create event classes and replace existing calls to events_trigger() and with new event classes containing legacy information properties.&lt;br /&gt;
* Add more events throughout the standard Moodle package in places where we have add_to_log(). Implement some_event::get_legacy_log_data() which returns original parameters of add_to_log() and remove it. Old add_to_log() function is called in core_event_base::trigger() automatically with original parameters.&lt;br /&gt;
* Add even more new events all over the place.&lt;br /&gt;
&lt;br /&gt;
The difficult part is defining the new event classes properly because we must not change them after the 2.6 release.&lt;br /&gt;
&lt;br /&gt;
== Stage 3 (requires partial completion of Stage 2) ==&lt;br /&gt;
&lt;br /&gt;
* Migrate current legacy event handlers to new handlers with one event class instance parameter, ex.: enrol plugins.&lt;br /&gt;
&lt;br /&gt;
== Stage 4 (requires partial completion of Stage 2) ==&lt;br /&gt;
&lt;br /&gt;
* Implement an event logging handler.&lt;br /&gt;
* Implement logging storage plugins.&lt;br /&gt;
* Define logging apis.&lt;br /&gt;
* Create new reports.&lt;br /&gt;
* Switch to new logging everywhere after Stage 2 has been completed and new reports are usable.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
== Stage 5  ==&lt;br /&gt;
&lt;br /&gt;
* Decide how much backwards compatibility we want for old log tables. Most probably they will get only legacy log data.&lt;br /&gt;
* Implement some BC solution for old code that reads log tables directly.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;br /&gt;
&lt;br /&gt;
== Stage 6 (requires completion of Stage 4 and 5) ==&lt;br /&gt;
&lt;br /&gt;
Moodle 2.8dev? This is the ultimate end of old logging via the &#039;&#039;log&#039;&#039; table.&lt;br /&gt;
&lt;br /&gt;
* Deprecate the add_to_log() function with a debug message and do nothing inside.&lt;br /&gt;
* Remove all legacy logging from event classes.&lt;br /&gt;
&lt;br /&gt;
See [[Logging 2]]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Matteo_Scaramuccia&amp;diff=38462</id>
		<title>User:Matteo Scaramuccia</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Matteo_Scaramuccia&amp;diff=38462"/>
		<updated>2013-03-20T13:45:08Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Created page with &amp;quot;OSS supporter.  ==See also==  * [https://moodle.org/user/view.php?id=1075386&amp;amp;course=1 My moodle.org profile]&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;OSS supporter.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [https://moodle.org/user/view.php?id=1075386&amp;amp;course=1 My moodle.org profile]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=jQuery&amp;diff=38459</id>
		<title>jQuery</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=jQuery&amp;diff=38459"/>
		<updated>2013-03-20T13:17:47Z</updated>

		<summary type="html">&lt;p&gt;Scaroodle: Fixed trivial typo. BTW, great job Petr!&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.5}}&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WORK IN PROGRESS see MDL-15727&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
[[YUI]] is the recommended library for development of Moodle plugins or customisations. However due to significant demand it will be possible to use also jQuery in Moodle add-ons.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===Basic jQuery in add-on theme===&lt;br /&gt;
&lt;br /&gt;
# create /theme/sometheme/lib.php file if it does not exist yet&lt;br /&gt;
# add new function theme_sometheme_page_init to the lib.php file (replace &#039;sometheme&#039; with real name of your theme)&lt;br /&gt;
# use jQuery JavaScript in theme layout files&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file: /theme/sometheme/lib.php&lt;br /&gt;
function theme_sometheme_page_init(moodle_page $page) {&lt;br /&gt;
    $page-&amp;gt;requires-&amp;gt;jquery();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
// near the end of file: /theme/sometheme/layout/general.php&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  $(&#039;.headermain&#039;).mouseover(function() {&lt;br /&gt;
    alert(&#039;grrr&#039;);&lt;br /&gt;
  });&lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===jQuery UI in add-on activity module===&lt;br /&gt;
# optionally add more jQuery plugins (not recommended because the same plugins in different add-ons may collide)&lt;br /&gt;
# add necessary $PAGE-&amp;gt;requires&lt;br /&gt;
# use jQuery&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
require(&#039;../../config.php&#039;);&lt;br /&gt;
&lt;br /&gt;
// ... normal PAGE and access control&lt;br /&gt;
&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery();&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui&#039;);&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui-css&#039;);&lt;br /&gt;
&lt;br /&gt;
echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
?&amp;gt;&lt;br /&gt;
    &amp;lt;button&amp;gt;A button element&amp;lt;/button&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;dialog&amp;quot; title=&amp;quot;Basic dialog&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;p&amp;gt;This is the default dialog which is useful for displaying information. The dialog window can be moved, resized and closed with the &#039;x&#039; icon.&amp;lt;/p&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;script&amp;gt;&lt;br /&gt;
        $(function() {&lt;br /&gt;
            $( &amp;quot;#dialog&amp;quot; ).dialog();&lt;br /&gt;
        });&lt;br /&gt;
    &amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
echo $OUTPUT-&amp;gt;footer();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===jQuery UI in add-on block===&lt;br /&gt;
# add necessary requires in get_required_javascript() method in your block, do not forget to call it in parent too&lt;br /&gt;
# use jQuery in blok html output&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
class block_html extends block_base {&lt;br /&gt;
&lt;br /&gt;
    function get_required_javascript() {&lt;br /&gt;
        parent::get_required_javascript();&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;requires-&amp;gt;jquery();&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui&#039;);&lt;br /&gt;
        $this-&amp;gt;page-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;ui-css&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    function get_content() {&lt;br /&gt;
&lt;br /&gt;
        // ....&lt;br /&gt;
&lt;br /&gt;
        $this-&amp;gt;content-&amp;gt;text .= &#039;&lt;br /&gt;
&amp;lt;div id=&amp;quot;progressbar&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;script&amp;gt;&lt;br /&gt;
  $(function() {&lt;br /&gt;
    $( &amp;quot;#progressbar&amp;quot; ).progressbar({&lt;br /&gt;
      value: 37&lt;br /&gt;
    });&lt;br /&gt;
  });&lt;br /&gt;
  &amp;lt;/script&amp;gt;&#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;
===Override base jQuery UI theme===&lt;br /&gt;
# download new jQuery UI theme and extract it into theme/sometheme/jquery/custom-1.0&lt;br /&gt;
# define new jQuery theme ui css plugin in theme/sometheme/jquery/plugins.php&lt;br /&gt;
# overrider core &#039;ui-css&#039; with &#039;yourtheme-ui-css&#039;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file: theme/sometheme/jquery/plugins.php&lt;br /&gt;
$plugins = array(&lt;br /&gt;
    &#039;some-ui-css&#039;  =&amp;gt; array(&#039;files&#039; =&amp;gt; array(&#039;custom-1.0/jquery-ui-1.10.2.custom.min.css&#039;)),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// file: /theme/sometheme/lib.php&lt;br /&gt;
function theme_sometheme_page_init(moodle_page $page) {&lt;br /&gt;
    // There is no need to $page-&amp;gt;requires-&amp;gt;jquery() if the theme does not use jQuery.&lt;br /&gt;
    $page-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;sometheme-ui-css&#039;, &#039;theme_sometheme&#039;);&lt;br /&gt;
    $page-&amp;gt;requires-&amp;gt;jquery_override_plugin(&#039;ui-css&#039;, &#039;sometheme-ui-css&#039;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Backwards compatibility for scripts written for older jQuery scripts===&lt;br /&gt;
&lt;br /&gt;
See [https://github.com/jquery/jquery-migrate/ jQuery Migrate plugin]&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$PAGE-&amp;gt;requires-&amp;gt;jquery_plugin(&#039;migrate&#039;); &lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===mymobile theme===&lt;br /&gt;
&lt;br /&gt;
See mymobile theme for more information including custom jQuery plugins, integration with jQuery Mobile.&lt;br /&gt;
&lt;br /&gt;
==More information==&lt;br /&gt;
&lt;br /&gt;
===jQuery plugin collisions===&lt;br /&gt;
&lt;br /&gt;
The loading order of plugins is defined by order of $PAGE-&amp;gt;requires. If there are plugins with the same name the first $PAGE-&amp;gt;require wins.&lt;br /&gt;
&lt;br /&gt;
It is recommended to use plugin overrides only in themes because multiple overrides of the same plugin result in undefined behaviour. In general themes should have more freedom to add extra jQuery plugins, other Moodle plugins should ideally use only basic jQuery or jQuery UI.&lt;br /&gt;
&lt;br /&gt;
===jQuery plugin modifications===&lt;br /&gt;
&lt;br /&gt;
Files in jQuery plugins MUST NOT be changed, always create a new file with different name and update CSS and plugins.php if necessary and delete the old file.&lt;br /&gt;
&lt;br /&gt;
===jQuery versions===&lt;br /&gt;
&lt;br /&gt;
Only minor jQuery version updates can be done in STABLE branches. Add-on developers must revalidate compatibility after every major upgrade. Use official &#039;migrate&#039; plugin if necessary, see example above.&lt;br /&gt;
&lt;br /&gt;
==Frequently asked questions==&lt;br /&gt;
&lt;br /&gt;
; Can I serve jQuery from CDN? : No, because CDNs do not include all plugins and some do not include https support. Use proxy caching such as Cloudflare instead.&lt;br /&gt;
&lt;br /&gt;
; I edited some file but the change is ignored, why? : See above, files MUST NOT be updated in jQuery plugins, always create new files or directories. Moodle cache purging does not have any effect on jQuery plugins.&lt;br /&gt;
&lt;br /&gt;
; Can we remove YUI now? : No! YUI is the only recommended JS library in Moodle add-ons and core.&lt;br /&gt;
&lt;br /&gt;
; Can I use different jQuery version? : No. (Theoretically you might try jQuery plugin override to include some later minor revision.)&lt;br /&gt;
&lt;br /&gt;
; Could we have jQuery plugin dependencies? : No, order your $PAGE-&amp;gt;requires manually.&lt;br /&gt;
&lt;br /&gt;
; Are there any performance costs when using jQuery? : Yes. Please consider using SimpleYUI for simple DOM manipulations or standard YUI widgets.&lt;br /&gt;
&lt;br /&gt;
; Can I use YUI loader to include jQuery? : No. Moodle jQuery support is not compatible with sandboxing.&lt;br /&gt;
&lt;br /&gt;
; Moodle complains when I disable slasharguments setting, why? : Please fix your server to be compatible with slasharguments, even IIS can support it now!&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [http://jquery.com jQuery]&lt;br /&gt;
* [http://jqueryui.com jQuery User Interface]&lt;/div&gt;</summary>
		<author><name>Scaroodle</name></author>
	</entry>
</feed>