<?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=Leonstr</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=Leonstr"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Leonstr"/>
	<updated>2026-04-10T23:55:11Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=64282</id>
		<title>lib/formslib.php Form Definition</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=64282"/>
		<updated>2024-08-16T14:36:24Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* select */ Outdent setSelected&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Formslib}}&lt;br /&gt;
== &#039;&#039;definition()&#039;&#039; ==&lt;br /&gt;
The definition of the elements to be included in the form, their &#039;types&#039; (PARAM_*), helpbuttons included, etc. is all included in a function you must define in your class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;definition()&#039;&#039; is used to define the elements in the form and &#039;&#039;&#039;this definition will be used for validating data submitted as well as for printing the form.&#039;&#039;&#039; For select and checkbox type elements only data that could have been selected will be allowed. And only data that corresponds to a form element in the definition will be accepted as submitted data.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;definition()&#039;&#039; should include all elements that are going to be used on form, some elements may be removed or tweaked later in &#039;&#039;definition_after_data()&#039;&#039;. Please do not create conditional elements in &#039;&#039;definition()&#039;&#039;, the definition() should not directly depend on the submitted data.&lt;br /&gt;
&lt;br /&gt;
Note that the definition function is called when the form class is instantiated. There is no option to (say) manipulate data in the class (that may affect the rendering of the form) between instantiating the form and calling any other methods. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;libdir/formslib.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
class simplehtml_form extends moodleform {&lt;br /&gt;
&lt;br /&gt;
    function definition() {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
       &lt;br /&gt;
        $mform = $this-&amp;gt;_form; // Don&#039;t forget the underscore! &lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement()... // Add elements to your form&lt;br /&gt;
            ...&lt;br /&gt;
    }                           // Close the function&lt;br /&gt;
}                               // Close the class&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===Passing parameters to the Form===&lt;br /&gt;
The constructor for &#039;&#039;moodleform&#039;&#039; allows a number of parameters including one (&#039;&#039;$customdata&#039;&#039;) to permit an array of arbitrary data to be passed to your form. &lt;br /&gt;
&lt;br /&gt;
For example, you can pass the data &amp;quot;$email&amp;quot; and &amp;quot;$username&amp;quot; to the Form&#039;s class for use inside (say) the definition.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform_simple = new simplehtml_form( null, array(&#039;email&#039;=&amp;gt;$email, &#039;username&#039;=&amp;gt;$username ) );&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
(the first parameter is $action, &#039;&#039;null&#039;&#039; will cause the form action to be determined automatically)&lt;br /&gt;
&lt;br /&gt;
Secondly, inside the form definition you can use those parameters to set the default values to some of the form&#039;s fields&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;), &#039;maxlength=&amp;quot;100&amp;quot; size=&amp;quot;25&amp;quot; &#039;);&lt;br /&gt;
 $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);&lt;br /&gt;
 $mform-&amp;gt;addRule(&#039;email&#039;, get_string(&#039;missingemail&#039;), &#039;required&#039;, null, &#039;server&#039;);&lt;br /&gt;
 // Set default value by using a passed parameter&lt;br /&gt;
 $mform-&amp;gt;setDefault(&#039;email&#039;,$this-&amp;gt;_customdata[&#039;email&#039;]);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Use Fieldsets to group Form Elements==&lt;br /&gt;
You use code like this to open a fieldset with a &#039;&#039;legend&#039;&#039;. &amp;lt;br /&amp;gt;&lt;br /&gt;
(&#039;&#039;&#039;Note&#039;&#039;&#039;: Some themes turn off legends on admin setting pages by using CSS: &amp;lt;nowiki&amp;gt;#adminsettings legend {display:none;}&amp;lt;/nowiki&amp;gt;.)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;header&#039;, &#039;nameforyourheaderelement&#039;, get_string(&#039;titleforlegened&#039;, &#039;modulename&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can&#039;t yet nest these visible fieldsets unfortunately. But in fact groups of elements are wrapped in invisible fieldsets.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
Since Moodle 2.5 fieldsets without any required fields are collapsed by default. To display these fieldsets on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To close a fieldset on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You close a fieldset with moodle_form&#039;s closeHeaderBefore method. You tell closeHeaderBefore the element before you wish to end the fieldset. A fieldset is automatically closed if you open a new one. You need to use this code only if you want to close a fieldset and the subsequent form elements are not to be enclosed by a visible fieldset (they are still enclosed with an invisible one with no legend) :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;closeHeaderBefore(&#039;buttonar&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==addElement==&lt;br /&gt;
Use the addElement method to add an element to a form. The first few arguments are always the same. The first param is the type of the element to add. The second is the elementname to use which is normally the html name of the element in the form. The third is often the text for the label for the element.&lt;br /&gt;
&lt;br /&gt;
Some examples are below :&lt;br /&gt;
=== button ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;button&#039;, &#039;intro&#039;, get_string(&amp;quot;buttonlabel&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A button element. If you want a submit or cancel button see &#039;submit&#039; element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== autocomplete ===&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
Available since Moodle 3.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$searchareas = \core_search\manager::get_search_areas_list(true);                                                           &lt;br /&gt;
$areanames = array();                                                                                                       &lt;br /&gt;
foreach ($searchareas as $areaid =&amp;gt; $searcharea) {                                                                          &lt;br /&gt;
    $areanames[$areaid] = $searcharea-&amp;gt;get_visible_name();                                                                  &lt;br /&gt;
}                                                                                                                           &lt;br /&gt;
$options = array(                                                                                                           &lt;br /&gt;
    &#039;multiple&#039; =&amp;gt; true,                                                  &lt;br /&gt;
    &#039;noselectionstring&#039; =&amp;gt; get_string(&#039;allareas&#039;, &#039;search&#039;),                                                                &lt;br /&gt;
);         &lt;br /&gt;
$mform-&amp;gt;addElement(&#039;autocomplete&#039;, &#039;areaids&#039;, get_string(&#039;searcharea&#039;, &#039;search&#039;), $areanames, $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The autocomplete element is an advanced form element that supports server-side searching - or simple filtering of a predefined list of options. Some benefits of using this form element are that it handles very large datasets extremely well - it has great accessibility built in - and it gives a good user experience. If you have so much data you need to build pagination into a page - you could probably come up with a better design using this. The simplest way to use it is compatible with the standard &#039;select&#039; form element. You give it a list of options and some parameters to configure how it behaves. The valid parameters for this simple mode of operation are:&lt;br /&gt;
* multiple (boolean - default false) - Allow more than one selected item. The data coming from the form will be an array in this case.&lt;br /&gt;
[[image:autocomplete_multiple2.png|center|thumb|alt=autocomplete with multiple option|autocomplete with multiple option.]]&lt;br /&gt;
* noselectionstring (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to display when nothing is selected.&lt;br /&gt;
* showsuggestions (boolean - default true) - Do not show the list of suggestions when the user starts typing.&lt;br /&gt;
* placeholder (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to show in the search box when it is empty.&lt;br /&gt;
* casesensitive (boolean - default false) - Is the search case sensitive ?&lt;br /&gt;
* tags (boolean - default false) - This changes the behaviour so that the user can create new valid entries in the list by typing them and pressing enter.&lt;br /&gt;
* ajax (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - This string is the name of an AMD module that can fetch and format results.&lt;br /&gt;
* valuehtmlcallback - For use with the AJAX option, so that it can format the initial value of the form field (available since Moodle 3.5)&lt;br /&gt;
More explanation on the &#039;ajax&#039; option. This should be the name of an AMD module that implements 2 functions:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Source of data for Ajax element.&lt;br /&gt;
 *&lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.&lt;br /&gt;
 * @param {String} query The query string.                        &lt;br /&gt;
 * @param {Function} callback A callback function receiving an array of results.&lt;br /&gt;
 * @param {Function} failure A callback function to be called in case of failure, receiving the error message.&lt;br /&gt;
 * @return {Void}                                                                                                           &lt;br /&gt;
*/                                                                                                                         &lt;br /&gt;
transport: function(selector, query, callback, failure) ...&lt;br /&gt;
&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Process the results for auto complete elements.                                                                          &lt;br /&gt;
 *                                                                                                                          &lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.                                                      &lt;br /&gt;
 * @param {Array} results An array or results.                                                                              &lt;br /&gt;
 * @return {Array} New array of results.                                                                                    &lt;br /&gt;
 */                                                                                                                         &lt;br /&gt;
processResults: function(selector, results)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A good example is here: [https://github.com/moodle/moodle/blob/master/admin/tool/lp/amd/src/frameworks_datasource.js admin/tool/lp/amd/src/frameworks_datasource.js]&lt;br /&gt;
&lt;br /&gt;
The &#039;valuehtmlcallback&#039; function is needed when an AJAX-supporting form field has an initial value that needs special rendering, similar to how the AJAX code would render it when the user changes it dynamically. For example, if the field contains user ids and its initial value is &#039;1,2&#039; then you want it to use the rendered HTML display for each value (probably a user&#039;s name and picture), not just display those numbers. Here is an example, from /search/classes/output/form/search.php:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&#039;valuehtmlcallback&#039; =&amp;gt; function($value) {&lt;br /&gt;
    global $DB, $OUTPUT;&lt;br /&gt;
    $user = $DB-&amp;gt;get_record(&#039;user&#039;, [&#039;id&#039; =&amp;gt; (int)$value], &#039;*&#039;, IGNORE_MISSING);&lt;br /&gt;
    if (!$user || !user_can_view_profile($user)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
    $details = user_get_user_details($user);&lt;br /&gt;
    return $OUTPUT-&amp;gt;render_from_template(&lt;br /&gt;
        &#039;core_search/form-user-selector-suggestion&#039;, $details);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The Mustache template used here is the same as the one used by the AJAX code when the field is changed dynamically.&lt;br /&gt;
&lt;br /&gt;
When using the ajax option in an mform with validation etc - it is recommended to sub-class the php class &amp;quot;MoodleQuickForm_autocomplete&amp;quot; so that you can provide a list of name and&lt;br /&gt;
values to populate the form element if the form is re-displayed due to a validation error. An example is [https://github.com/moodle/moodle/blob/MOODLE_31_STABLE/admin/tool/lp/classes/form/framework_autocomplete.php admin/tool/lp/classes/form/framework_autocomplete.php].&lt;br /&gt;
&lt;br /&gt;
We have provided several useful subclasses of this form element already that are simple to use (course and tags).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt; &lt;br /&gt;
    // Course example.&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;multiple&#039; - boolean multi select                                                                      &lt;br /&gt;
    //                       &#039;exclude&#039; - array or int, list of course ids to never show                                             &lt;br /&gt;
    //                       &#039;requiredcapabilities&#039; - array of capabilities. Uses ANY to combine them.                              &lt;br /&gt;
    //                       &#039;limittoenrolled&#039; - boolean Limits to enrolled courses.                                                &lt;br /&gt;
    //                       &#039;includefrontpage&#039; - boolean Enables the frontpage to be selected.  &lt;br /&gt;
    $options = array(&#039;multiple&#039; =&amp;gt; true, &#039;includefrontpage&#039; =&amp;gt; true);                                                           &lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course&#039;, &#039;mappedcourses&#039;, get_string(&#039;courses&#039;), $options); &lt;br /&gt;
&lt;br /&gt;
    // Tags&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;showstandard&#039; - boolean One of the core_tag_tag constants to say which tags to display&lt;br /&gt;
    //                       &#039;component&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    //                       &#039;itemtype&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;tags&#039;, &#039;interests&#039;, get_string(&#039;interestslist&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;user&#039;, &#039;component&#039; =&amp;gt; &#039;core&#039;));     &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== checkbox ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a simple checkbox. The third parameter for this element is the label to display on the left side of the form. You can also supply a string as a fourth parameter to specify a label that will appear on the right of the element. Checkboxes and radio buttons can be grouped and have individual labels on their right.&lt;br /&gt;
&lt;br /&gt;
You can have a 5th parameter $attributes, as on other elements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BEWARE:&#039;&#039;&#039; Unchecked checkboxes return nothing at all (as if they didn&#039;t exist). This can surprise the unwary. You may wish to use advcheckbox instead, which does return a value when not checked. &#039;Advcheckbox&#039; eliminates this problem. &lt;br /&gt;
==== advcheckbox ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;), &#039;Label displayed after checkbox&#039;, array(&#039;group&#039; =&amp;gt; 1), array(0, 1));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Similar to the checkbox above, but with some important improvements:&lt;br /&gt;
# The (optional) 5th parameter is a normal $attributes array, normally used to set HTML attributes for the &amp;lt;input&amp;gt; element. However, a special value of &#039;group&#039; can be given, which will add a class name to the element, and enable its grouping for a [[lib/formslib.php_add_checkbox_controller|checkbox controller]]&lt;br /&gt;
#The (optional) 6th parameter is an array of values that will be associated with the checked/unchecked state of the checkbox. With a normal checkbox you cannot choose that value, and in fact an unchecked checkbox will not even be sent with the form data.&lt;br /&gt;
#It returns a 0 value when unchecked. Compare with the ordinary checkbox which does not return anything at all.&lt;br /&gt;
=== choosecoursefile ===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;choosecoursefile&#039;, &#039;mediafile&#039;, get_string(&#039;mediafile&#039;, &#039;lesson&#039;), array(&#039;courseid&#039;=&amp;gt;$COURSE-&amp;gt;id));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Choose a file from the course files area. The fourth option is a list of options for the element. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: This has been superceded by [[#filepicker|filepicker]] in Moodle 2.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&#039;courseid&#039; =&amp;gt;null,  //if it is null (default then use global $COURSE&lt;br /&gt;
      &#039;height&#039;   =&amp;gt;500,   // height of the popup window&lt;br /&gt;
      &#039;width&#039;    =&amp;gt;750,   // width of the popup window&lt;br /&gt;
      &#039;options&#039;  =&amp;gt;&#039;none&#039;); //options string for the pop up window &lt;br /&gt;
                          //eg. &#039;menubar=0,location=0,scrollbars,resizable&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;maxlength&#039; =&amp;gt; 255, &#039;size&#039; =&amp;gt; 48)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the maxlength / size of the text box (note size will default to 48 if not specified)&lt;br /&gt;
&lt;br /&gt;
Finally, as this element is a group containing two elements (button + value), you can add validation rules by using the &#039;&#039;&#039;addGroupRule()&#039;&#039;&#039; method in this (complex) way:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;elementname&#039;, array(&#039;value&#039; =&amp;gt; array(array(list, of, rule, params, but, fieldname))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Where: &#039;&#039;&#039;&amp;quot;elementname&amp;quot;&#039;&#039;&#039; is the name of the choosecoursefile group element, &#039;&#039;&#039;&amp;quot;value&amp;quot;&#039;&#039;&#039; is the name of the text field within the group and the &#039;&#039;&#039;&amp;quot;list, of, addrule, params, but, fieldname&amp;quot;&#039;&#039;&#039; is exactly that, the list of fields in the normal addRule() function but ommiting the first one, the fieldname.&lt;br /&gt;
&lt;br /&gt;
For example, the [http://cvs.moodle.org/moodle/mod/resource/type/file/resource.class.php?view=markup file/url resource type], uses one &amp;quot;choosecoursefile&amp;quot; element, and it controls the maximum length of the field (255) with this use of addGroupRule():&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;reference&#039;, array(&#039;value&#039; =&amp;gt; array(array(get_string(&#039;maximumchars&#039;, &#039;&#039;, 255), &#039;maxlength&#039;, 255, &#039;client&#039;))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== date_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_selector&#039;, &#039;assesstimefinish&#039;, get_string(&#039;to&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a date selector. You can select a Day, Month and Year using a group of select boxes. The fourth param here is an array of options. The defaults for the options are :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;optional&#039;  =&amp;gt; false&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. You can supply a fifth param of attributes here as well.&lt;br /&gt;
=== date_time_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_time_selector&#039;, &#039;assesstimestart&#039;, get_string(&#039;from&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a group of select boxes to select a date (Day Month and Year) and time (Hour and Minute). When submitted, submitted data is processed and a timestamp is passed to $form-&amp;gt;get_data(); the fourth param here is an array of options. The defaults for the options are:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;step&#039;      =&amp;gt; 5,&lt;br /&gt;
    &#039;optional&#039; =&amp;gt; false,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. Setting &#039;optional&#039; to true adds an &#039;enable&#039; checkbox to the selector. You can supply a fifth param of attributes here as well.&lt;br /&gt;
===duration===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;duration&#039;, &#039;timelimit&#039;, get_string(&#039;timelimit&#039;, &#039;quiz&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This field type lets the user input an interval of time. It comprises a text field, where you can type a number, and a dropdown for selecting a unit (days, hours, minutes or seconds). When submitted the value is converted to a number of seconds.&lt;br /&gt;
&lt;br /&gt;
You can add a fourth parameter to give options. At the moment the only option supported is here is an array of options. The defaults for the options is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;optional&#039; =&amp;gt; true)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;size&#039; =&amp;gt; 5)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the size of the text box.&lt;br /&gt;
=== editor ===&lt;br /&gt;
This replaces the old htmleditor field type. It allows the user to enter rich text content in a variety of formats.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;fieldname&#039;, get_string(&#039;labeltext&#039;, &#039;langfile&#039;));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;fieldname&#039;, PARAM_RAW);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
NOTE: It won&#039;t work properly without the setType() as shown.&lt;br /&gt;
&lt;br /&gt;
If you would like to let the user use the filepicker to upload images etc. that are used in the content, then see [[Using_the_File_API_in_Moodle_forms]].&lt;br /&gt;
&lt;br /&gt;
You can supply a fifth param to htmleditor of an array of options that are mostly related to file handling:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;subdirs&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxbytes&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxfiles&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;changeformat&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;context&#039;=&amp;gt;null,&lt;br /&gt;
    &#039;noclean&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;trusttext&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;enable_filemanagement&#039; =&amp;gt; true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The option &#039;enable_filemanagement&#039; will display the file management button on true and remove it on false.&lt;br /&gt;
&lt;br /&gt;
To save the data if you don&#039;t care about files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$text     = $formdata-&amp;gt;fieldname[&#039;text&#039;];&lt;br /&gt;
$format   = $formdata-&amp;gt;fieldname[&#039;format&#039;];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: Because the text editor might be &amp;quot;Atto&amp;quot; (depending on user preferences) and Atto has an &amp;quot;autosave&amp;quot; feature - it requires that the combination of $PAGE-&amp;gt;url and this elementid are unique. If not, the autosaved text for a different form may be restored into this form.&lt;br /&gt;
=== file ===&lt;br /&gt;
File upload input box with browse button. In the form definition type&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
after form submission and validation use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If there is no requirement to save the file, you can read the file contents directly into a string as follows...&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    $mform-&amp;gt;get_file_content(&#039;attachment&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you need advanced settings such as required file, different max upload size or name of uploaded file&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0, true, true, false));&lt;br /&gt;
            $mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
            $mform-&amp;gt;addRule(&#039;attachment&#039;, null, &#039;required&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
    $newfilename = $mform-&amp;gt;get_new_filename();&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When porting old code it is also possible to use the upload manager directly for processing of uploaded files.&lt;br /&gt;
&lt;br /&gt;
Please note that if using set_upload_manager() it must be before addElement(&#039;file&#039;,..).&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
File uploading was rewritten in 2.0. Please see inline docs for now. This page will be updated when the new API stabilises.&lt;br /&gt;
===filepicker===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
General replacement of &#039;&#039;file&#039;&#039; element.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null, array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See also [[Using the File API in Moodle forms]]&lt;br /&gt;
=== hidden ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;hidden&#039;, &#039;reply&#039;, &#039;yes&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A hidden element. Set the element name (in this case &#039;&#039;&#039;reply&#039;&#039;&#039;) to the stated value (in this case &#039;&#039;&#039;yes&#039;&#039;&#039;).&lt;br /&gt;
=== html ===&lt;br /&gt;
You can add arbitrary HTML to your Moodle form:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;html&#039;, &#039;&amp;lt;div class=&amp;quot;qheader&amp;quot;&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See [http://moodle.org/mod/forum/discuss.php?d=126935 &amp;quot;Question: Can I put a moodleform inside a table td?&amp;quot;] for a concrete example.&lt;br /&gt;
=== htmleditor &amp;amp; format ===&lt;br /&gt;
These elements are now deprecated. Please use the [[#editor|editor]] field type instead.&lt;br /&gt;
===modgrade===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modgrade&#039;, &#039;scale&#039;, get_string(&#039;grade&#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade for any activity module. The fourth argument is whether to include an option for no grade which has a value 0. This select box does include scales. The default is true, include no grade option.&lt;br /&gt;
&lt;br /&gt;
A helpbutton is automatically added.&lt;br /&gt;
===modvisible===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modvisible&#039;, &#039;visible&#039;, get_string(&#039;visible&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade visibility in an activity mod update form.&lt;br /&gt;
===password===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;password&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element. Fourth param is an array or string of attributes.&lt;br /&gt;
===passwordunmask===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;passwordunmask&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element with option to show the password in plaintext. Fourth param is an array or string of attributes.&lt;br /&gt;
=== radio ===&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$radioarray=array();&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;yes&#039;), 1, $attributes);&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;no&#039;), 0, $attributes);&lt;br /&gt;
$mform-&amp;gt;addGroup($radioarray, &#039;radioar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Second param names the radio button and should be the same for each button in the group in order to toggle correctly. Third param would be the label for the form element but is generally ignored as this element will always be in a group which has it&#039;s own label. Fourth param is a string, a label to be displayed on the right of the element. The fifth is the value for this radio button. $attributes can be a string or an array of attributes.&lt;br /&gt;
&lt;br /&gt;
It is possible to add help to individual radio buttons but this requires a custom template to be defined for the group elements. See MDL-15571.&lt;br /&gt;
&lt;br /&gt;
Since 2.3 it cannot be statically called anymore, so we need to call createElement from $mform reference.&lt;br /&gt;
==== setDefault ====&lt;br /&gt;
To set the default for a radio button group as above use the following :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;yesno&#039;, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This would make the default &#039;no&#039;.&lt;br /&gt;
===select===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;type&#039;, get_string(&#039;forumtype&#039;, &#039;forum&#039;), $FORUM_TYPES, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The fourth param for this element is an array of options for the select box. The keys are the values for the option and the value of the array is the text for the option. The fifth param $attributes is optional, see text element for description of attributes param.&lt;br /&gt;
&lt;br /&gt;
It is also possible to create a select with certain options disabled, using [http://stackoverflow.com/questions/2138089/how-can-i-use-quickform-to-add-disabled-select-options/2150275#2150275 this technique].&lt;br /&gt;
&lt;br /&gt;
You can set an &#039;onchange&#039; attribute when adding or creating the select element: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$form-&amp;gt;addElement(&#039;select&#039;, &#039;iselTest&#039;, &#039;Test Select:&#039;, $arrayOfOptions, array(&#039;onchange&#039; =&amp;gt; &#039;javascript:myFunctionToDoSomething();&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====multi-select====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), array(&#039;red&#039;, &#039;blue&#039;, &#039;green&#039;), $attributes);&lt;br /&gt;
$select-&amp;gt;setMultiple(true);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====setSelected====&lt;br /&gt;
To set the default selected item in a select element, you can use the &#039;setSelected&#039; method. The &#039;setSelected&#039; can either get a value or an array of values.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array(&lt;br /&gt;
    &#039;ff0000&#039; =&amp;gt; &#039;Red&#039;,&lt;br /&gt;
    &#039;00ff00&#039; =&amp;gt; &#039;Green&#039;,&lt;br /&gt;
    &#039;0000ff&#039; =&amp;gt; &#039;Blue&#039;&lt;br /&gt;
);&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), $options);&lt;br /&gt;
// This will select the colour blue.&lt;br /&gt;
$select-&amp;gt;setSelected(&#039;0000ff&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or for multiple-selection:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$skillsarray = array(&lt;br /&gt;
    &#039;val1&#039; =&amp;gt; &#039;Skill A&#039;,&lt;br /&gt;
    &#039;val2&#039; =&amp;gt; &#039;Skill B&#039;,&lt;br /&gt;
    &#039;val3&#039; =&amp;gt; &#039;Skill C&#039;&lt;br /&gt;
);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;md_skills&#039;, get_string(&#039;skills&#039;, &#039;metadata&#039;), $skillsarray);&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setMultiple(true);&lt;br /&gt;
// This will select the skills A and B.&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setSelected(array(&#039;val1&#039;, &#039;val2&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
However you probably don&#039;t want to do this. Instead you probably want to use setDefault, or set it using the form&#039;s setData method.&lt;br /&gt;
&lt;br /&gt;
===selectyesno===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;maxbytes&#039;, get_string(&#039;maxattachmentsize&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you want a yes / no select box this one automatically translates itself and has value 1 for yes and 0 for no.&lt;br /&gt;
===selectwithlink===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array();&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectwithlink&#039;, &#039;scaleid&#039;, get_string(&#039;scale&#039;), $options, null, &lt;br /&gt;
    array(&#039;link&#039; =&amp;gt; $CFG-&amp;gt;wwwroot.&#039;/grade/edit/scale/edit.php?courseid=&#039;.$COURSE-&amp;gt;id, &#039;label&#039; =&amp;gt; get_string(&#039;scalescustomcreate&#039;)));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
select type element with options containing link&lt;br /&gt;
===static===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;description&#039;, &#039;exercise&#039;),&lt;br /&gt;
    get_string(&#039;descriptionofexercise&#039;, &#039;exercise&#039;, $COURSE-&amp;gt;students));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a static element. It should be used with care if it is used to display a static piece of text with a label. The third param is the label and the fourth is the static text itself.&lt;br /&gt;
===submit, reset and cancel===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//normally you use add_action_buttons instead of this code&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;reset&#039;, &#039;resetbutton&#039;, get_string(&#039;revert&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;cancel&#039;);&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, &#039; &#039;, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A &#039;Submit&#039; type element is a submit type form element which will submit the form. A &#039;Reset&#039; will not submit the form but will reset any changes the user has made to form contents. A &#039;Cancel&#039; element cancels form submission. You need to have a branch in your code before you check for get_data() to check if submission has been cancelled with is_cancelled(); See the example on the usage page.&lt;br /&gt;
&lt;br /&gt;
You should name your submit and reset buttons &#039;submitbutton&#039; and &#039;resetbutton&#039; or something similar (not &#039;submit&#039; and &#039;reset&#039;). This avoids problems in JavaScript of collisions between form element names and names of JavaScript methods of the form object.&lt;br /&gt;
====add_action_buttons($cancel = true, $submitlabel=null);====&lt;br /&gt;
You will normally use this helper function which is a method of moodleform to add all the &#039;action&#039; buttons to the end of your form. A boolean parameter allow you to specify whether to include a cancel button and specify the label for your submit button (pass the result of get_string). Default for the submit button label is get_string(&#039;savechanges&#039;). Note the &#039;&#039;&#039;$this&#039;&#039;&#039; not &#039;&#039;&#039;$mform&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===text===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;name&#039;, get_string(&#039;forumname&#039;, &#039;forum&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For a simple text input element. (For text labels, use the &#039;static&#039; element.) Your fourth parameter here can be a string or array of attributes for the text element. The following are equivalent :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$attributes=&#039;size=&amp;quot;20&amp;quot;&#039;;&lt;br /&gt;
$attributes=array(&#039;size&#039;=&amp;gt;&#039;20&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Generally you are encouraged to use CSS instead of using attributes for styling.&lt;br /&gt;
&lt;br /&gt;
===float===&lt;br /&gt;
{{Moodle 3.7}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;float&#039;, &#039;defaultmark&#039;, get_string(&#039;defaultmark&#039;, &#039;question&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use the float element if you want a text box to get a floating point number. This element automatically supports localised decimal separators. You don&#039;t need to use setType with the float element.&lt;br /&gt;
&lt;br /&gt;
===textarea===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;textarea&#039;, &#039;introduction&#039;, get_string(&amp;quot;introtext&amp;quot;, &amp;quot;survey&amp;quot;), &#039;wrap=&amp;quot;virtual&amp;quot; rows=&amp;quot;20&amp;quot; cols=&amp;quot;50&amp;quot;&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A textarea element. If you want an htmleditor use htmleditor element. Fourth element here is a string or array of attributes.&lt;br /&gt;
===recaptcha===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;recaptcha&#039;, &#039;recaptcha_field_name&#039;, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use this recaptcha element to reduce the spam risk in your forms. Third element here is a string or array of attributes. Take care to get an API key from http://recaptcha.net/api/getkey before using this element.&lt;br /&gt;
&lt;br /&gt;
To check whether recaptcha is enabled at site level use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (!empty($CFG-&amp;gt;recaptchapublickey) &amp;amp;&amp;amp; !empty($CFG-&amp;gt;recaptchaprivatekey)) {&lt;br /&gt;
    //recaptcha is enabled&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===tags===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;field_name&#039;, $lable, $options, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Used for editing a list of tags, for example on a blog post.&lt;br /&gt;
&lt;br /&gt;
There is only one option available, &#039;display&#039;, which should be set to one of the contstants MoodleQuickForm_tags::ONLYOFFICIAL, NOOFFICIAL or DEFAULTUI. This controls whether the official tags are listed for easy selection, or a text area where arbitrary tags may be typed, or both. The default is both.&lt;br /&gt;
&lt;br /&gt;
The value should be set/returned as an array of tags.&lt;br /&gt;
===grading===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;grading&#039;, &#039;advancedgrading&#039;, get_string(&#039;grade&#039;).&#039;:&#039;, array(&#039;gradinginstance&#039; =&amp;gt; $gradinginstance));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Custom element for advanced grading plugins.&lt;br /&gt;
&lt;br /&gt;
When adding the &#039;grading&#039; element to the form, developer must pass an object of class gradingform_instance as $attributes[&#039;gradinginstance&#039;]. Otherwise an exception will be thrown.&lt;br /&gt;
===questioncategory===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;questioncategory&#039;, &#039;category&#039;, get_string(&#039;category&#039;, &#039;question&#039;),&lt;br /&gt;
    array(&#039;contexts&#039;=&amp;gt;$contexts, &#039;top&#039;=&amp;gt;true, &#039;currentcat&#039;=&amp;gt;$currentcat, &#039;nochildrenof&#039;=&amp;gt;$currentcat));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates a drop down element to select a question category.&lt;br /&gt;
&lt;br /&gt;
Options are:&lt;br /&gt;
&#039;&#039;&#039;contexts&#039;&#039;&#039; - (required) context in which question appears&lt;br /&gt;
&#039;&#039;&#039;currentcat&#039;&#039;&#039; - (optional) course category&lt;br /&gt;
&#039;&#039;&#039;top&#039;&#039;&#039; - (optional) if true will put top categories on top&lt;br /&gt;
&#039;&#039;&#039;nochildrenof&#039;&#039;&#039; - (optional) Format categories into an indented list reflecting the tree structure&lt;br /&gt;
=== filetypes ===&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
Available since Moodle 3.4&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;allowedfiletypes&#039;, get_string(&#039;allowedfiletypes&#039;, &#039;tool_myplugin&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates an input element allowing the user to specify file types for the given purpose. The typical scenario is a setting that allows the teacher define a list of allowed file types submitted by students.&lt;br /&gt;
&lt;br /&gt;
The element allows the user to either type the list of filetypes manually, or select the types from the list. Also supported is selecting the whole group of file types - such as &amp;quot;image&amp;quot;. The element integrates with the [[Core filetypes]] system so all default types and groups are presented, as well as those [[:en:Working with files#Site administration settings|defined locally by the admin]].&lt;br /&gt;
&lt;br /&gt;
As the list can be types in manually, the form processing code should always normalize it first via the provided utility methods:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$allowedfiletypes = $filetypesutil-&amp;gt;normalize_file_types($formdata-&amp;gt;allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This always returns an array of recognized valid values. The original list can be separated by whitespace, end of lines, commas, colons and semicolons. During the normalization, values are converted to lowercase, empty valies and duplicates are removed. Glob evaluation is not supported.&lt;br /&gt;
&lt;br /&gt;
The normalization should also happen if the previously defined list had been saved to the database and re-read for actual usage. The normalization output value can be directly used as the accepted_types option for the filepicker.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$options[&#039;accepted_types&#039;] = $filetypesutil-&amp;gt;normalize_file_types($allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
By default, user input is validated against the list of known file types and groups. This validation can be disabled via options.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Supported options&#039;&#039;&#039;&lt;br /&gt;
; onlytypes : Allow selection from these file types only; for example [&#039;onlytypes&#039; =&amp;gt; [&#039;web_image&#039;]].&lt;br /&gt;
; allowall : Allow to select &#039;All file types&#039;, defaults to true. Does not apply with onlytypes are set.&lt;br /&gt;
; allowunknown : Skip implicit validation against the list of known file types.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;doctypes&#039;, get_string(&#039;doctypes&#039;, &#039;tool_myplugin&#039;), [&#039;onlytypes&#039; =&amp;gt; [&#039;document&#039;], &#039;allowunknown&#039; =&amp;gt; true]);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==addGroup==&lt;br /&gt;
A &#039;group&#039; in formslib is just a group of elements that will have a label and will be included on one line. &lt;br /&gt;
&lt;br /&gt;
For example typical code to include a submit and cancel button on the same line : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;cancel&#039;, get_string(&#039;cancel&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You use the same arguments for createElement as you do for addElement. Any label for the element in the third argument is normally ignored (but not in the case of the submit buttons above where the third argument is not for a label but is the text for the button).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a bad example (don&#039;t do this for real, use the &#039;optional&#039; =&amp;gt; true option of the date element): putting a date_selector (which is itself a group of elements) and a checkbox on the same line, note that you can disable every element in the group using the group name &#039;availablefromgroup&#039; but it doesn&#039;t disable the controlling element the &#039;availablefromenabled&#039; checkbox:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$availablefromgroup=array();&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;date_selector&#039;, &#039;availablefrom&#039;, &#039;&#039;);&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;availablefromenabled&#039;, &#039;&#039;, get_string(&#039;enable&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($availablefromgroup, &#039;availablefromgroup&#039;, get_string(&#039;availablefromdate&#039;, &#039;data&#039;), &#039;&amp;amp;nbsp;&#039;, false);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;availablefromgroup&#039;, &#039;availablefromenabled&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you want to put a group inside another array so that you can repeat items, use createElement instead of addGroup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* By default, groups modify the names of elements inside them by appending a number. This is often unhelpful, for example if you want to use disabledIf on the element. To prevent this behaviour, set the last parameter to false when creating a group.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems, null, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==addRule==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;elementname&#039;, get_string(&#039;error&#039;), &#039;rule type&#039;, &#039;extraruledata&#039;, &#039;server&#039;(default), false, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first param(element) is an element name and second(message) is the error message that will be displayed to the user.&lt;br /&gt;
The third parameter(type) is the type of rule. The fourth param(format) is used for extra data needed with some rules such as minlength and regex. The fifth parameter(validation) validates input data on server or client side, if validation is done on client side then it will be checked on the server side as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 * @param    string     $element       Form element name&lt;br /&gt;
 * @param    string     $message       Message to display for invalid data&lt;br /&gt;
 * @param    string     $type          Rule type, use getRegisteredRules() to get types&lt;br /&gt;
 * @param    string     $format        (optional)Required for extra rule data&lt;br /&gt;
 * @param    string     $validation    (optional)Where to perform validation: &amp;quot;server&amp;quot;, &amp;quot;client&amp;quot;&lt;br /&gt;
 * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?&lt;br /&gt;
 * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Common Rule Types&#039;&#039;&#039;&lt;br /&gt;
* required &lt;br /&gt;
* maxlength&lt;br /&gt;
* minlength&lt;br /&gt;
* rangelength&lt;br /&gt;
* email&lt;br /&gt;
* regex&lt;br /&gt;
* lettersonly&lt;br /&gt;
* alphanumeric&lt;br /&gt;
* numeric&lt;br /&gt;
* nopunctuation&lt;br /&gt;
* nonzero&lt;br /&gt;
* callback&lt;br /&gt;
* compare&lt;br /&gt;
===Server side and Client side===&lt;br /&gt;
In case you use the &#039;&#039;Client side&#039;&#039; validation option, you can mainly check for an empty or not input field. unless you write some &#039;&#039;Client side&#039;&#039; code which will probably be JavaScript functions to verify the data inside the input fields before it is submitted to the server. It could save some time if those functions are short, simple and quick to compute.&lt;br /&gt;
In case you need a more complex validation checks which relay on Moodle&#039;s internal PHP libraries (or other/external PHP libraries) you better use the &#039;&#039;Server side&#039;&#039; validation checks. Where you can query the DB, write complex PHP validation functions and much much more, that are not available (easily) when using JavaScript on the client&#039;s side.&lt;br /&gt;
==addHelpButton==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;api_key_field&#039;, &#039;api_key&#039;, &#039;block_extsearch&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The following parameters are expected:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param $elementname The name of the form element to add the help button for&lt;br /&gt;
 * @param $identifier The identifier for the help string and its title (see below)&lt;br /&gt;
 * @param $component The component name to look for the help string in&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# get_string($identifier, $component) // The title of the help page&lt;br /&gt;
# get_string(&amp;quot;{$identifier}_help&amp;quot;, $component) // The content of the help page&lt;br /&gt;
So you will need to have &#039;&#039;&#039;$identifier&#039;&#039;&#039; and &#039;&#039;&#039;{$identifier}_help&#039;&#039;&#039; defined in order for the help button to be created properly. For example the multiple choice question editing form has a button for shuffling the answers. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;shuffleanswers&#039;, &#039;shuffleanswers&#039;, &#039;qtype_multichoice&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and so the language file includes the strings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers&#039;] = &#039;Shuffle the choices?&#039;; &lt;br /&gt;
$string[&#039;shuffleanswers_help&#039;] = &#039;If enabled,.....&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also add the language string like&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers_link&#039;] = &#039;question/shuffleanswers&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to add a link to more help on Moodle docs. See [[String_API]] for more information about help icons.&lt;br /&gt;
==setDefault==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), $grades);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;grade&#039;, array(&#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), &#039;exercise&#039;));&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;grade&#039;, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Set the default of the form value with setDefault($elementname, $value); where elementname is the elementname whose default you want to set and $value is the default to set. We set the defaults for the form in definition(). This default is what is used if no data is loaded into the form with set_data(); eg. on display of the form for an &#039;add&#039; rather than &#039;update&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;desc&#039;, get_string(&#039;description&#039;));     &lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;desc&#039;, array(&#039;text&#039;=&amp;gt;$defaulttext));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that when setting the default for an editor element you must use an array to define the default &amp;quot;text&amp;quot; value as shown above.&lt;br /&gt;
==disabledIf==&lt;br /&gt;
For any element or groups of element in a form you can conditionally disable the group or individual element depending on conditions.&lt;br /&gt;
&lt;br /&gt;
You can use $mform-&amp;gt;disabledIf($elementName, $dependentOn, $condition = &#039;notchecked&#039;, $value=&#039;1&#039;)&lt;br /&gt;
* elementname can be a group. If you specify a group all elements in the group will be disabled (if dependentOn is in elementname group that is ignored and not disabled). These are the element names you&#039;ve used as the second argument in addElement or addGroup.&lt;br /&gt;
* dependentOn is the actual name of the element as it will appear in html. This can be different to the name used in addGroup particularly but also addElement where you&#039;re adding a complex element like a date_selector. Check the html of your page. You typically make the depedentOn a checkbox or select box.&lt;br /&gt;
* $condition will be &#039;notchecked&#039;, &#039;checked&#039;, &#039;noitemselected&#039;, &#039;eq&#039;, &#039;in&#039; or, if it is anything else, we test for &#039;neq&#039;.&lt;br /&gt;
** If $condition is &#039;eq&#039; or &#039;neq&#039; then we check the value of the dependentOn field and check for equality (==) or nonequality (!=) in js&lt;br /&gt;
** If $condition is &#039;checked&#039; or &#039;notchecked&#039; then we check to see if a checkbox is checked or not.&lt;br /&gt;
** If $condition is &#039;in&#039; then we check to see if a selected item is in the given list or not. (This was introduced in Moodle 2.7+)&lt;br /&gt;
** If $condition is &#039;noitemselected&#039; then we check to see whether nothing is selected in a dropdown list.&lt;br /&gt;
Examples:&lt;br /&gt;
 // Disable my control unless a checkbox is checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control if a checkbox &#039;&#039;&#039;is&#039;&#039;&#039; checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;, &#039;checked&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control when a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;eq&#039;, 42);&lt;br /&gt;
&lt;br /&gt;
 // Disable my control unless a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;neq&#039;, 42);&lt;br /&gt;
The possible choices here are in the dependency manager in lib/form/form.js.&lt;br /&gt;
===A tricky case===&lt;br /&gt;
You need to take care with disabledIf if you plan to use it with groups of checkboxes.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have a group of 5 checkboxes and you want to enable a depending item such as a drop down menu only when the first and the last checkboxes are selected.&lt;br /&gt;
&lt;br /&gt;
To fix ideas:&lt;br /&gt;
&lt;br /&gt;
If the selection in the checkboxes group is:&lt;br /&gt;
 mycheck_01 == 1&lt;br /&gt;
 mycheck_02 == 0&lt;br /&gt;
 mycheck_03 == 0&lt;br /&gt;
 mycheck_04 == 0&lt;br /&gt;
 mycheck_05 == 1&lt;br /&gt;
the depending item must be enabled while ANY OTHER COMBINATION must disable the drop down menu.&lt;br /&gt;
&lt;br /&gt;
The following code will, apparently, fail:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In fact, once you get the drop down menu enabled, you are free to unselect mycheck_01 whilst still having the depending item enabled.&lt;br /&gt;
This apparent bug occurs because a non-checked checkbox behaves like a non existing mform element. So the js code will not find the element &amp;quot;mycheck_01&amp;quot; and will not apply the corresponding rule.&lt;br /&gt;
&lt;br /&gt;
A working solution for this kind of issue seems to be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;notchecked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;notchecked&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To see a failing example as the one described, try the attachments provided in MDL-38975. See also in MDL-38975 for the working solution in action with modifications suggested by Eloy.&lt;br /&gt;
==hideIf==&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
For any element or groups of element in a form you can conditionally hide the group or individual element depending on conditions.&lt;br /&gt;
This uses the same syntax as disabledIf just with hideIf instead.&lt;br /&gt;
==setType==&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned. These should be used for get parameters such as id, course etc. which are used to load a page and also with setType(); method. Every form element should have a type specified except select, radio box and checkbox elements, these elements do a good job of cleaning themselves (only specified options are allowed as user input).&lt;br /&gt;
===Most Commonly Used PARAM_* Types===&lt;br /&gt;
These are the most commonly used PARAM_* types and their proper uses. More types can be seen in moodlelib.php starting around line 100. For the full list, see the file lib/moodlelib.php.&lt;br /&gt;
* PARAM_CLEAN is deprecated and you should try to use a more specific type.&lt;br /&gt;
* PARAM_TEXT should be used for cleaning data that is expected to contain multi-lang content. It will strip all html tags. But will still let tags for multilang support through.&lt;br /&gt;
* PARAM_NOTAGS should be used for cleaning data that is expected to be plain text. It will strip *all* html type tags. It will *not* let tags for multilang support through. This should be used for instance for email addresses where no multilang support is appropriate.&lt;br /&gt;
* PARAM_RAW means no cleaning whatsoever, it is used mostly for data from the html editor. Data from the editor is later cleaned before display using format_text() function. PARAM_RAW can also be used for data that is validated by some other way or printed by p() or s().&lt;br /&gt;
* PARAM_INT should be used for integers. PARAM_FLOAT is also available for decimal numbers but is not recommended for user input since it does not work for languages that use , as a decimal separator.&lt;br /&gt;
&lt;br /&gt;
These types are deprecated:&lt;br /&gt;
* PARAM_CLEAN obsoleted, please use a more specific type of parameter. @deprecated since 2.0&lt;br /&gt;
* PARAM_ACTION deprecated alias for PARAM_ALPHA use for various actions in forms and urls. Use PARAM_ALPHANUMEXT instead.&lt;br /&gt;
&lt;br /&gt;
==disable_form_change_checker==&lt;br /&gt;
By default, any Moodle form will pop-up an &amp;quot;Are you sure?&amp;quot; alert if you make some changes and then try to leave the page without saving. Occasionally, that is undesirable, in which case you can call&lt;br /&gt;
 $mform-&amp;gt;disable_form_change_checker()&lt;br /&gt;
&lt;br /&gt;
==RTL support==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
As of Moodle 3.2, some form elements have been refined to better support right-to-left languages. In RTL, most fields should not have their direction flipped, a URL, a path to a file, a number, ... are always displayed LTR. Input fields and text areas now will best guess whether they should be forced to be displayed in LTR based on the PARAM type associated with it. You can call:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setForceLtr(&#039;name&#039;, true/false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
on some form fields (like &#039;text&#039;) to manually set the value, and for directionality.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* [http://www.midnighthax.com/quickform.php PEAR HTML QuickForm Getting Started Guide] by Keith Edmunds of Midnighthax.com&lt;br /&gt;
* [http://pear.php.net/manual/en/package.html.html-quickform.php PEAR::HTML_QuickForm manual]&lt;br /&gt;
[[Category:Formslib]]&lt;br /&gt;
[[Category:Interfaces]]&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=64281</id>
		<title>lib/formslib.php Form Definition</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=64281"/>
		<updated>2024-08-16T14:33:36Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* select */ Add &amp;lt;pre&amp;gt; for code sample&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Formslib}}&lt;br /&gt;
== &#039;&#039;definition()&#039;&#039; ==&lt;br /&gt;
The definition of the elements to be included in the form, their &#039;types&#039; (PARAM_*), helpbuttons included, etc. is all included in a function you must define in your class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;definition()&#039;&#039; is used to define the elements in the form and &#039;&#039;&#039;this definition will be used for validating data submitted as well as for printing the form.&#039;&#039;&#039; For select and checkbox type elements only data that could have been selected will be allowed. And only data that corresponds to a form element in the definition will be accepted as submitted data.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;definition()&#039;&#039; should include all elements that are going to be used on form, some elements may be removed or tweaked later in &#039;&#039;definition_after_data()&#039;&#039;. Please do not create conditional elements in &#039;&#039;definition()&#039;&#039;, the definition() should not directly depend on the submitted data.&lt;br /&gt;
&lt;br /&gt;
Note that the definition function is called when the form class is instantiated. There is no option to (say) manipulate data in the class (that may affect the rendering of the form) between instantiating the form and calling any other methods. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;libdir/formslib.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
class simplehtml_form extends moodleform {&lt;br /&gt;
&lt;br /&gt;
    function definition() {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
       &lt;br /&gt;
        $mform = $this-&amp;gt;_form; // Don&#039;t forget the underscore! &lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement()... // Add elements to your form&lt;br /&gt;
            ...&lt;br /&gt;
    }                           // Close the function&lt;br /&gt;
}                               // Close the class&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===Passing parameters to the Form===&lt;br /&gt;
The constructor for &#039;&#039;moodleform&#039;&#039; allows a number of parameters including one (&#039;&#039;$customdata&#039;&#039;) to permit an array of arbitrary data to be passed to your form. &lt;br /&gt;
&lt;br /&gt;
For example, you can pass the data &amp;quot;$email&amp;quot; and &amp;quot;$username&amp;quot; to the Form&#039;s class for use inside (say) the definition.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform_simple = new simplehtml_form( null, array(&#039;email&#039;=&amp;gt;$email, &#039;username&#039;=&amp;gt;$username ) );&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
(the first parameter is $action, &#039;&#039;null&#039;&#039; will cause the form action to be determined automatically)&lt;br /&gt;
&lt;br /&gt;
Secondly, inside the form definition you can use those parameters to set the default values to some of the form&#039;s fields&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;), &#039;maxlength=&amp;quot;100&amp;quot; size=&amp;quot;25&amp;quot; &#039;);&lt;br /&gt;
 $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);&lt;br /&gt;
 $mform-&amp;gt;addRule(&#039;email&#039;, get_string(&#039;missingemail&#039;), &#039;required&#039;, null, &#039;server&#039;);&lt;br /&gt;
 // Set default value by using a passed parameter&lt;br /&gt;
 $mform-&amp;gt;setDefault(&#039;email&#039;,$this-&amp;gt;_customdata[&#039;email&#039;]);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Use Fieldsets to group Form Elements==&lt;br /&gt;
You use code like this to open a fieldset with a &#039;&#039;legend&#039;&#039;. &amp;lt;br /&amp;gt;&lt;br /&gt;
(&#039;&#039;&#039;Note&#039;&#039;&#039;: Some themes turn off legends on admin setting pages by using CSS: &amp;lt;nowiki&amp;gt;#adminsettings legend {display:none;}&amp;lt;/nowiki&amp;gt;.)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;header&#039;, &#039;nameforyourheaderelement&#039;, get_string(&#039;titleforlegened&#039;, &#039;modulename&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can&#039;t yet nest these visible fieldsets unfortunately. But in fact groups of elements are wrapped in invisible fieldsets.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
Since Moodle 2.5 fieldsets without any required fields are collapsed by default. To display these fieldsets on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To close a fieldset on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You close a fieldset with moodle_form&#039;s closeHeaderBefore method. You tell closeHeaderBefore the element before you wish to end the fieldset. A fieldset is automatically closed if you open a new one. You need to use this code only if you want to close a fieldset and the subsequent form elements are not to be enclosed by a visible fieldset (they are still enclosed with an invisible one with no legend) :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;closeHeaderBefore(&#039;buttonar&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==addElement==&lt;br /&gt;
Use the addElement method to add an element to a form. The first few arguments are always the same. The first param is the type of the element to add. The second is the elementname to use which is normally the html name of the element in the form. The third is often the text for the label for the element.&lt;br /&gt;
&lt;br /&gt;
Some examples are below :&lt;br /&gt;
=== button ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;button&#039;, &#039;intro&#039;, get_string(&amp;quot;buttonlabel&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A button element. If you want a submit or cancel button see &#039;submit&#039; element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== autocomplete ===&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
Available since Moodle 3.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$searchareas = \core_search\manager::get_search_areas_list(true);                                                           &lt;br /&gt;
$areanames = array();                                                                                                       &lt;br /&gt;
foreach ($searchareas as $areaid =&amp;gt; $searcharea) {                                                                          &lt;br /&gt;
    $areanames[$areaid] = $searcharea-&amp;gt;get_visible_name();                                                                  &lt;br /&gt;
}                                                                                                                           &lt;br /&gt;
$options = array(                                                                                                           &lt;br /&gt;
    &#039;multiple&#039; =&amp;gt; true,                                                  &lt;br /&gt;
    &#039;noselectionstring&#039; =&amp;gt; get_string(&#039;allareas&#039;, &#039;search&#039;),                                                                &lt;br /&gt;
);         &lt;br /&gt;
$mform-&amp;gt;addElement(&#039;autocomplete&#039;, &#039;areaids&#039;, get_string(&#039;searcharea&#039;, &#039;search&#039;), $areanames, $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The autocomplete element is an advanced form element that supports server-side searching - or simple filtering of a predefined list of options. Some benefits of using this form element are that it handles very large datasets extremely well - it has great accessibility built in - and it gives a good user experience. If you have so much data you need to build pagination into a page - you could probably come up with a better design using this. The simplest way to use it is compatible with the standard &#039;select&#039; form element. You give it a list of options and some parameters to configure how it behaves. The valid parameters for this simple mode of operation are:&lt;br /&gt;
* multiple (boolean - default false) - Allow more than one selected item. The data coming from the form will be an array in this case.&lt;br /&gt;
[[image:autocomplete_multiple2.png|center|thumb|alt=autocomplete with multiple option|autocomplete with multiple option.]]&lt;br /&gt;
* noselectionstring (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to display when nothing is selected.&lt;br /&gt;
* showsuggestions (boolean - default true) - Do not show the list of suggestions when the user starts typing.&lt;br /&gt;
* placeholder (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to show in the search box when it is empty.&lt;br /&gt;
* casesensitive (boolean - default false) - Is the search case sensitive ?&lt;br /&gt;
* tags (boolean - default false) - This changes the behaviour so that the user can create new valid entries in the list by typing them and pressing enter.&lt;br /&gt;
* ajax (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - This string is the name of an AMD module that can fetch and format results.&lt;br /&gt;
* valuehtmlcallback - For use with the AJAX option, so that it can format the initial value of the form field (available since Moodle 3.5)&lt;br /&gt;
More explanation on the &#039;ajax&#039; option. This should be the name of an AMD module that implements 2 functions:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Source of data for Ajax element.&lt;br /&gt;
 *&lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.&lt;br /&gt;
 * @param {String} query The query string.                        &lt;br /&gt;
 * @param {Function} callback A callback function receiving an array of results.&lt;br /&gt;
 * @param {Function} failure A callback function to be called in case of failure, receiving the error message.&lt;br /&gt;
 * @return {Void}                                                                                                           &lt;br /&gt;
*/                                                                                                                         &lt;br /&gt;
transport: function(selector, query, callback, failure) ...&lt;br /&gt;
&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Process the results for auto complete elements.                                                                          &lt;br /&gt;
 *                                                                                                                          &lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.                                                      &lt;br /&gt;
 * @param {Array} results An array or results.                                                                              &lt;br /&gt;
 * @return {Array} New array of results.                                                                                    &lt;br /&gt;
 */                                                                                                                         &lt;br /&gt;
processResults: function(selector, results)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A good example is here: [https://github.com/moodle/moodle/blob/master/admin/tool/lp/amd/src/frameworks_datasource.js admin/tool/lp/amd/src/frameworks_datasource.js]&lt;br /&gt;
&lt;br /&gt;
The &#039;valuehtmlcallback&#039; function is needed when an AJAX-supporting form field has an initial value that needs special rendering, similar to how the AJAX code would render it when the user changes it dynamically. For example, if the field contains user ids and its initial value is &#039;1,2&#039; then you want it to use the rendered HTML display for each value (probably a user&#039;s name and picture), not just display those numbers. Here is an example, from /search/classes/output/form/search.php:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&#039;valuehtmlcallback&#039; =&amp;gt; function($value) {&lt;br /&gt;
    global $DB, $OUTPUT;&lt;br /&gt;
    $user = $DB-&amp;gt;get_record(&#039;user&#039;, [&#039;id&#039; =&amp;gt; (int)$value], &#039;*&#039;, IGNORE_MISSING);&lt;br /&gt;
    if (!$user || !user_can_view_profile($user)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
    $details = user_get_user_details($user);&lt;br /&gt;
    return $OUTPUT-&amp;gt;render_from_template(&lt;br /&gt;
        &#039;core_search/form-user-selector-suggestion&#039;, $details);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The Mustache template used here is the same as the one used by the AJAX code when the field is changed dynamically.&lt;br /&gt;
&lt;br /&gt;
When using the ajax option in an mform with validation etc - it is recommended to sub-class the php class &amp;quot;MoodleQuickForm_autocomplete&amp;quot; so that you can provide a list of name and&lt;br /&gt;
values to populate the form element if the form is re-displayed due to a validation error. An example is [https://github.com/moodle/moodle/blob/MOODLE_31_STABLE/admin/tool/lp/classes/form/framework_autocomplete.php admin/tool/lp/classes/form/framework_autocomplete.php].&lt;br /&gt;
&lt;br /&gt;
We have provided several useful subclasses of this form element already that are simple to use (course and tags).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt; &lt;br /&gt;
    // Course example.&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;multiple&#039; - boolean multi select                                                                      &lt;br /&gt;
    //                       &#039;exclude&#039; - array or int, list of course ids to never show                                             &lt;br /&gt;
    //                       &#039;requiredcapabilities&#039; - array of capabilities. Uses ANY to combine them.                              &lt;br /&gt;
    //                       &#039;limittoenrolled&#039; - boolean Limits to enrolled courses.                                                &lt;br /&gt;
    //                       &#039;includefrontpage&#039; - boolean Enables the frontpage to be selected.  &lt;br /&gt;
    $options = array(&#039;multiple&#039; =&amp;gt; true, &#039;includefrontpage&#039; =&amp;gt; true);                                                           &lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course&#039;, &#039;mappedcourses&#039;, get_string(&#039;courses&#039;), $options); &lt;br /&gt;
&lt;br /&gt;
    // Tags&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;showstandard&#039; - boolean One of the core_tag_tag constants to say which tags to display&lt;br /&gt;
    //                       &#039;component&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    //                       &#039;itemtype&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;tags&#039;, &#039;interests&#039;, get_string(&#039;interestslist&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;user&#039;, &#039;component&#039; =&amp;gt; &#039;core&#039;));     &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== checkbox ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a simple checkbox. The third parameter for this element is the label to display on the left side of the form. You can also supply a string as a fourth parameter to specify a label that will appear on the right of the element. Checkboxes and radio buttons can be grouped and have individual labels on their right.&lt;br /&gt;
&lt;br /&gt;
You can have a 5th parameter $attributes, as on other elements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BEWARE:&#039;&#039;&#039; Unchecked checkboxes return nothing at all (as if they didn&#039;t exist). This can surprise the unwary. You may wish to use advcheckbox instead, which does return a value when not checked. &#039;Advcheckbox&#039; eliminates this problem. &lt;br /&gt;
==== advcheckbox ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;), &#039;Label displayed after checkbox&#039;, array(&#039;group&#039; =&amp;gt; 1), array(0, 1));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Similar to the checkbox above, but with some important improvements:&lt;br /&gt;
# The (optional) 5th parameter is a normal $attributes array, normally used to set HTML attributes for the &amp;lt;input&amp;gt; element. However, a special value of &#039;group&#039; can be given, which will add a class name to the element, and enable its grouping for a [[lib/formslib.php_add_checkbox_controller|checkbox controller]]&lt;br /&gt;
#The (optional) 6th parameter is an array of values that will be associated with the checked/unchecked state of the checkbox. With a normal checkbox you cannot choose that value, and in fact an unchecked checkbox will not even be sent with the form data.&lt;br /&gt;
#It returns a 0 value when unchecked. Compare with the ordinary checkbox which does not return anything at all.&lt;br /&gt;
=== choosecoursefile ===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;choosecoursefile&#039;, &#039;mediafile&#039;, get_string(&#039;mediafile&#039;, &#039;lesson&#039;), array(&#039;courseid&#039;=&amp;gt;$COURSE-&amp;gt;id));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Choose a file from the course files area. The fourth option is a list of options for the element. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: This has been superceded by [[#filepicker|filepicker]] in Moodle 2.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&#039;courseid&#039; =&amp;gt;null,  //if it is null (default then use global $COURSE&lt;br /&gt;
      &#039;height&#039;   =&amp;gt;500,   // height of the popup window&lt;br /&gt;
      &#039;width&#039;    =&amp;gt;750,   // width of the popup window&lt;br /&gt;
      &#039;options&#039;  =&amp;gt;&#039;none&#039;); //options string for the pop up window &lt;br /&gt;
                          //eg. &#039;menubar=0,location=0,scrollbars,resizable&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;maxlength&#039; =&amp;gt; 255, &#039;size&#039; =&amp;gt; 48)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the maxlength / size of the text box (note size will default to 48 if not specified)&lt;br /&gt;
&lt;br /&gt;
Finally, as this element is a group containing two elements (button + value), you can add validation rules by using the &#039;&#039;&#039;addGroupRule()&#039;&#039;&#039; method in this (complex) way:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;elementname&#039;, array(&#039;value&#039; =&amp;gt; array(array(list, of, rule, params, but, fieldname))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Where: &#039;&#039;&#039;&amp;quot;elementname&amp;quot;&#039;&#039;&#039; is the name of the choosecoursefile group element, &#039;&#039;&#039;&amp;quot;value&amp;quot;&#039;&#039;&#039; is the name of the text field within the group and the &#039;&#039;&#039;&amp;quot;list, of, addrule, params, but, fieldname&amp;quot;&#039;&#039;&#039; is exactly that, the list of fields in the normal addRule() function but ommiting the first one, the fieldname.&lt;br /&gt;
&lt;br /&gt;
For example, the [http://cvs.moodle.org/moodle/mod/resource/type/file/resource.class.php?view=markup file/url resource type], uses one &amp;quot;choosecoursefile&amp;quot; element, and it controls the maximum length of the field (255) with this use of addGroupRule():&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;reference&#039;, array(&#039;value&#039; =&amp;gt; array(array(get_string(&#039;maximumchars&#039;, &#039;&#039;, 255), &#039;maxlength&#039;, 255, &#039;client&#039;))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== date_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_selector&#039;, &#039;assesstimefinish&#039;, get_string(&#039;to&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a date selector. You can select a Day, Month and Year using a group of select boxes. The fourth param here is an array of options. The defaults for the options are :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;optional&#039;  =&amp;gt; false&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. You can supply a fifth param of attributes here as well.&lt;br /&gt;
=== date_time_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_time_selector&#039;, &#039;assesstimestart&#039;, get_string(&#039;from&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a group of select boxes to select a date (Day Month and Year) and time (Hour and Minute). When submitted, submitted data is processed and a timestamp is passed to $form-&amp;gt;get_data(); the fourth param here is an array of options. The defaults for the options are:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;step&#039;      =&amp;gt; 5,&lt;br /&gt;
    &#039;optional&#039; =&amp;gt; false,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. Setting &#039;optional&#039; to true adds an &#039;enable&#039; checkbox to the selector. You can supply a fifth param of attributes here as well.&lt;br /&gt;
===duration===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;duration&#039;, &#039;timelimit&#039;, get_string(&#039;timelimit&#039;, &#039;quiz&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This field type lets the user input an interval of time. It comprises a text field, where you can type a number, and a dropdown for selecting a unit (days, hours, minutes or seconds). When submitted the value is converted to a number of seconds.&lt;br /&gt;
&lt;br /&gt;
You can add a fourth parameter to give options. At the moment the only option supported is here is an array of options. The defaults for the options is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;optional&#039; =&amp;gt; true)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;size&#039; =&amp;gt; 5)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the size of the text box.&lt;br /&gt;
=== editor ===&lt;br /&gt;
This replaces the old htmleditor field type. It allows the user to enter rich text content in a variety of formats.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;fieldname&#039;, get_string(&#039;labeltext&#039;, &#039;langfile&#039;));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;fieldname&#039;, PARAM_RAW);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
NOTE: It won&#039;t work properly without the setType() as shown.&lt;br /&gt;
&lt;br /&gt;
If you would like to let the user use the filepicker to upload images etc. that are used in the content, then see [[Using_the_File_API_in_Moodle_forms]].&lt;br /&gt;
&lt;br /&gt;
You can supply a fifth param to htmleditor of an array of options that are mostly related to file handling:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;subdirs&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxbytes&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxfiles&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;changeformat&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;context&#039;=&amp;gt;null,&lt;br /&gt;
    &#039;noclean&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;trusttext&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;enable_filemanagement&#039; =&amp;gt; true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The option &#039;enable_filemanagement&#039; will display the file management button on true and remove it on false.&lt;br /&gt;
&lt;br /&gt;
To save the data if you don&#039;t care about files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$text     = $formdata-&amp;gt;fieldname[&#039;text&#039;];&lt;br /&gt;
$format   = $formdata-&amp;gt;fieldname[&#039;format&#039;];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: Because the text editor might be &amp;quot;Atto&amp;quot; (depending on user preferences) and Atto has an &amp;quot;autosave&amp;quot; feature - it requires that the combination of $PAGE-&amp;gt;url and this elementid are unique. If not, the autosaved text for a different form may be restored into this form.&lt;br /&gt;
=== file ===&lt;br /&gt;
File upload input box with browse button. In the form definition type&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
after form submission and validation use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If there is no requirement to save the file, you can read the file contents directly into a string as follows...&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    $mform-&amp;gt;get_file_content(&#039;attachment&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you need advanced settings such as required file, different max upload size or name of uploaded file&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0, true, true, false));&lt;br /&gt;
            $mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
            $mform-&amp;gt;addRule(&#039;attachment&#039;, null, &#039;required&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
    $newfilename = $mform-&amp;gt;get_new_filename();&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When porting old code it is also possible to use the upload manager directly for processing of uploaded files.&lt;br /&gt;
&lt;br /&gt;
Please note that if using set_upload_manager() it must be before addElement(&#039;file&#039;,..).&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
File uploading was rewritten in 2.0. Please see inline docs for now. This page will be updated when the new API stabilises.&lt;br /&gt;
===filepicker===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
General replacement of &#039;&#039;file&#039;&#039; element.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null, array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See also [[Using the File API in Moodle forms]]&lt;br /&gt;
=== hidden ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;hidden&#039;, &#039;reply&#039;, &#039;yes&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A hidden element. Set the element name (in this case &#039;&#039;&#039;reply&#039;&#039;&#039;) to the stated value (in this case &#039;&#039;&#039;yes&#039;&#039;&#039;).&lt;br /&gt;
=== html ===&lt;br /&gt;
You can add arbitrary HTML to your Moodle form:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;html&#039;, &#039;&amp;lt;div class=&amp;quot;qheader&amp;quot;&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See [http://moodle.org/mod/forum/discuss.php?d=126935 &amp;quot;Question: Can I put a moodleform inside a table td?&amp;quot;] for a concrete example.&lt;br /&gt;
=== htmleditor &amp;amp; format ===&lt;br /&gt;
These elements are now deprecated. Please use the [[#editor|editor]] field type instead.&lt;br /&gt;
===modgrade===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modgrade&#039;, &#039;scale&#039;, get_string(&#039;grade&#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade for any activity module. The fourth argument is whether to include an option for no grade which has a value 0. This select box does include scales. The default is true, include no grade option.&lt;br /&gt;
&lt;br /&gt;
A helpbutton is automatically added.&lt;br /&gt;
===modvisible===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modvisible&#039;, &#039;visible&#039;, get_string(&#039;visible&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade visibility in an activity mod update form.&lt;br /&gt;
===password===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;password&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element. Fourth param is an array or string of attributes.&lt;br /&gt;
===passwordunmask===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;passwordunmask&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element with option to show the password in plaintext. Fourth param is an array or string of attributes.&lt;br /&gt;
=== radio ===&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$radioarray=array();&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;yes&#039;), 1, $attributes);&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;no&#039;), 0, $attributes);&lt;br /&gt;
$mform-&amp;gt;addGroup($radioarray, &#039;radioar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Second param names the radio button and should be the same for each button in the group in order to toggle correctly. Third param would be the label for the form element but is generally ignored as this element will always be in a group which has it&#039;s own label. Fourth param is a string, a label to be displayed on the right of the element. The fifth is the value for this radio button. $attributes can be a string or an array of attributes.&lt;br /&gt;
&lt;br /&gt;
It is possible to add help to individual radio buttons but this requires a custom template to be defined for the group elements. See MDL-15571.&lt;br /&gt;
&lt;br /&gt;
Since 2.3 it cannot be statically called anymore, so we need to call createElement from $mform reference.&lt;br /&gt;
==== setDefault ====&lt;br /&gt;
To set the default for a radio button group as above use the following :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;yesno&#039;, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This would make the default &#039;no&#039;.&lt;br /&gt;
===select===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;type&#039;, get_string(&#039;forumtype&#039;, &#039;forum&#039;), $FORUM_TYPES, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The fourth param for this element is an array of options for the select box. The keys are the values for the option and the value of the array is the text for the option. The fifth param $attributes is optional, see text element for description of attributes param.&lt;br /&gt;
&lt;br /&gt;
It is also possible to create a select with certain options disabled, using [http://stackoverflow.com/questions/2138089/how-can-i-use-quickform-to-add-disabled-select-options/2150275#2150275 this technique].&lt;br /&gt;
&lt;br /&gt;
You can set an &#039;onchange&#039; attribute when adding or creating the select element: &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$form-&amp;gt;addElement(&#039;select&#039;, &#039;iselTest&#039;, &#039;Test Select:&#039;, $arrayOfOptions, array(&#039;onchange&#039; =&amp;gt; &#039;javascript:myFunctionToDoSomething();&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====multi-select====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), array(&#039;red&#039;, &#039;blue&#039;, &#039;green&#039;), $attributes);&lt;br /&gt;
$select-&amp;gt;setMultiple(true);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====setSelected=====&lt;br /&gt;
To set the default selected item in a select element, you can use the &#039;setSelected&#039; method. The &#039;setSelected&#039; can either get a value or an array of values.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array(&lt;br /&gt;
    &#039;ff0000&#039; =&amp;gt; &#039;Red&#039;,&lt;br /&gt;
    &#039;00ff00&#039; =&amp;gt; &#039;Green&#039;,&lt;br /&gt;
    &#039;0000ff&#039; =&amp;gt; &#039;Blue&#039;&lt;br /&gt;
);&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), $options);&lt;br /&gt;
// This will select the colour blue.&lt;br /&gt;
$select-&amp;gt;setSelected(&#039;0000ff&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or for multiple-selection:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$skillsarray = array(&lt;br /&gt;
    &#039;val1&#039; =&amp;gt; &#039;Skill A&#039;,&lt;br /&gt;
    &#039;val2&#039; =&amp;gt; &#039;Skill B&#039;,&lt;br /&gt;
    &#039;val3&#039; =&amp;gt; &#039;Skill C&#039;&lt;br /&gt;
);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;md_skills&#039;, get_string(&#039;skills&#039;, &#039;metadata&#039;), $skillsarray);&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setMultiple(true);&lt;br /&gt;
// This will select the skills A and B.&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setSelected(array(&#039;val1&#039;, &#039;val2&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
However you probably don&#039;t want to do this. Instead you probably want to use setDefault, or set it using the form&#039;s setData method.&lt;br /&gt;
&lt;br /&gt;
===selectyesno===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;maxbytes&#039;, get_string(&#039;maxattachmentsize&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you want a yes / no select box this one automatically translates itself and has value 1 for yes and 0 for no.&lt;br /&gt;
===selectwithlink===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array();&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectwithlink&#039;, &#039;scaleid&#039;, get_string(&#039;scale&#039;), $options, null, &lt;br /&gt;
    array(&#039;link&#039; =&amp;gt; $CFG-&amp;gt;wwwroot.&#039;/grade/edit/scale/edit.php?courseid=&#039;.$COURSE-&amp;gt;id, &#039;label&#039; =&amp;gt; get_string(&#039;scalescustomcreate&#039;)));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
select type element with options containing link&lt;br /&gt;
===static===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;description&#039;, &#039;exercise&#039;),&lt;br /&gt;
    get_string(&#039;descriptionofexercise&#039;, &#039;exercise&#039;, $COURSE-&amp;gt;students));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a static element. It should be used with care if it is used to display a static piece of text with a label. The third param is the label and the fourth is the static text itself.&lt;br /&gt;
===submit, reset and cancel===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//normally you use add_action_buttons instead of this code&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;reset&#039;, &#039;resetbutton&#039;, get_string(&#039;revert&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;cancel&#039;);&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, &#039; &#039;, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A &#039;Submit&#039; type element is a submit type form element which will submit the form. A &#039;Reset&#039; will not submit the form but will reset any changes the user has made to form contents. A &#039;Cancel&#039; element cancels form submission. You need to have a branch in your code before you check for get_data() to check if submission has been cancelled with is_cancelled(); See the example on the usage page.&lt;br /&gt;
&lt;br /&gt;
You should name your submit and reset buttons &#039;submitbutton&#039; and &#039;resetbutton&#039; or something similar (not &#039;submit&#039; and &#039;reset&#039;). This avoids problems in JavaScript of collisions between form element names and names of JavaScript methods of the form object.&lt;br /&gt;
====add_action_buttons($cancel = true, $submitlabel=null);====&lt;br /&gt;
You will normally use this helper function which is a method of moodleform to add all the &#039;action&#039; buttons to the end of your form. A boolean parameter allow you to specify whether to include a cancel button and specify the label for your submit button (pass the result of get_string). Default for the submit button label is get_string(&#039;savechanges&#039;). Note the &#039;&#039;&#039;$this&#039;&#039;&#039; not &#039;&#039;&#039;$mform&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===text===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;name&#039;, get_string(&#039;forumname&#039;, &#039;forum&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For a simple text input element. (For text labels, use the &#039;static&#039; element.) Your fourth parameter here can be a string or array of attributes for the text element. The following are equivalent :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$attributes=&#039;size=&amp;quot;20&amp;quot;&#039;;&lt;br /&gt;
$attributes=array(&#039;size&#039;=&amp;gt;&#039;20&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Generally you are encouraged to use CSS instead of using attributes for styling.&lt;br /&gt;
&lt;br /&gt;
===float===&lt;br /&gt;
{{Moodle 3.7}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;float&#039;, &#039;defaultmark&#039;, get_string(&#039;defaultmark&#039;, &#039;question&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use the float element if you want a text box to get a floating point number. This element automatically supports localised decimal separators. You don&#039;t need to use setType with the float element.&lt;br /&gt;
&lt;br /&gt;
===textarea===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;textarea&#039;, &#039;introduction&#039;, get_string(&amp;quot;introtext&amp;quot;, &amp;quot;survey&amp;quot;), &#039;wrap=&amp;quot;virtual&amp;quot; rows=&amp;quot;20&amp;quot; cols=&amp;quot;50&amp;quot;&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A textarea element. If you want an htmleditor use htmleditor element. Fourth element here is a string or array of attributes.&lt;br /&gt;
===recaptcha===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;recaptcha&#039;, &#039;recaptcha_field_name&#039;, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use this recaptcha element to reduce the spam risk in your forms. Third element here is a string or array of attributes. Take care to get an API key from http://recaptcha.net/api/getkey before using this element.&lt;br /&gt;
&lt;br /&gt;
To check whether recaptcha is enabled at site level use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (!empty($CFG-&amp;gt;recaptchapublickey) &amp;amp;&amp;amp; !empty($CFG-&amp;gt;recaptchaprivatekey)) {&lt;br /&gt;
    //recaptcha is enabled&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===tags===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;field_name&#039;, $lable, $options, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Used for editing a list of tags, for example on a blog post.&lt;br /&gt;
&lt;br /&gt;
There is only one option available, &#039;display&#039;, which should be set to one of the contstants MoodleQuickForm_tags::ONLYOFFICIAL, NOOFFICIAL or DEFAULTUI. This controls whether the official tags are listed for easy selection, or a text area where arbitrary tags may be typed, or both. The default is both.&lt;br /&gt;
&lt;br /&gt;
The value should be set/returned as an array of tags.&lt;br /&gt;
===grading===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;grading&#039;, &#039;advancedgrading&#039;, get_string(&#039;grade&#039;).&#039;:&#039;, array(&#039;gradinginstance&#039; =&amp;gt; $gradinginstance));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Custom element for advanced grading plugins.&lt;br /&gt;
&lt;br /&gt;
When adding the &#039;grading&#039; element to the form, developer must pass an object of class gradingform_instance as $attributes[&#039;gradinginstance&#039;]. Otherwise an exception will be thrown.&lt;br /&gt;
===questioncategory===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;questioncategory&#039;, &#039;category&#039;, get_string(&#039;category&#039;, &#039;question&#039;),&lt;br /&gt;
    array(&#039;contexts&#039;=&amp;gt;$contexts, &#039;top&#039;=&amp;gt;true, &#039;currentcat&#039;=&amp;gt;$currentcat, &#039;nochildrenof&#039;=&amp;gt;$currentcat));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates a drop down element to select a question category.&lt;br /&gt;
&lt;br /&gt;
Options are:&lt;br /&gt;
&#039;&#039;&#039;contexts&#039;&#039;&#039; - (required) context in which question appears&lt;br /&gt;
&#039;&#039;&#039;currentcat&#039;&#039;&#039; - (optional) course category&lt;br /&gt;
&#039;&#039;&#039;top&#039;&#039;&#039; - (optional) if true will put top categories on top&lt;br /&gt;
&#039;&#039;&#039;nochildrenof&#039;&#039;&#039; - (optional) Format categories into an indented list reflecting the tree structure&lt;br /&gt;
=== filetypes ===&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
Available since Moodle 3.4&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;allowedfiletypes&#039;, get_string(&#039;allowedfiletypes&#039;, &#039;tool_myplugin&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates an input element allowing the user to specify file types for the given purpose. The typical scenario is a setting that allows the teacher define a list of allowed file types submitted by students.&lt;br /&gt;
&lt;br /&gt;
The element allows the user to either type the list of filetypes manually, or select the types from the list. Also supported is selecting the whole group of file types - such as &amp;quot;image&amp;quot;. The element integrates with the [[Core filetypes]] system so all default types and groups are presented, as well as those [[:en:Working with files#Site administration settings|defined locally by the admin]].&lt;br /&gt;
&lt;br /&gt;
As the list can be types in manually, the form processing code should always normalize it first via the provided utility methods:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$allowedfiletypes = $filetypesutil-&amp;gt;normalize_file_types($formdata-&amp;gt;allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This always returns an array of recognized valid values. The original list can be separated by whitespace, end of lines, commas, colons and semicolons. During the normalization, values are converted to lowercase, empty valies and duplicates are removed. Glob evaluation is not supported.&lt;br /&gt;
&lt;br /&gt;
The normalization should also happen if the previously defined list had been saved to the database and re-read for actual usage. The normalization output value can be directly used as the accepted_types option for the filepicker.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$options[&#039;accepted_types&#039;] = $filetypesutil-&amp;gt;normalize_file_types($allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
By default, user input is validated against the list of known file types and groups. This validation can be disabled via options.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Supported options&#039;&#039;&#039;&lt;br /&gt;
; onlytypes : Allow selection from these file types only; for example [&#039;onlytypes&#039; =&amp;gt; [&#039;web_image&#039;]].&lt;br /&gt;
; allowall : Allow to select &#039;All file types&#039;, defaults to true. Does not apply with onlytypes are set.&lt;br /&gt;
; allowunknown : Skip implicit validation against the list of known file types.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;doctypes&#039;, get_string(&#039;doctypes&#039;, &#039;tool_myplugin&#039;), [&#039;onlytypes&#039; =&amp;gt; [&#039;document&#039;], &#039;allowunknown&#039; =&amp;gt; true]);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==addGroup==&lt;br /&gt;
A &#039;group&#039; in formslib is just a group of elements that will have a label and will be included on one line. &lt;br /&gt;
&lt;br /&gt;
For example typical code to include a submit and cancel button on the same line : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;cancel&#039;, get_string(&#039;cancel&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You use the same arguments for createElement as you do for addElement. Any label for the element in the third argument is normally ignored (but not in the case of the submit buttons above where the third argument is not for a label but is the text for the button).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a bad example (don&#039;t do this for real, use the &#039;optional&#039; =&amp;gt; true option of the date element): putting a date_selector (which is itself a group of elements) and a checkbox on the same line, note that you can disable every element in the group using the group name &#039;availablefromgroup&#039; but it doesn&#039;t disable the controlling element the &#039;availablefromenabled&#039; checkbox:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$availablefromgroup=array();&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;date_selector&#039;, &#039;availablefrom&#039;, &#039;&#039;);&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;availablefromenabled&#039;, &#039;&#039;, get_string(&#039;enable&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($availablefromgroup, &#039;availablefromgroup&#039;, get_string(&#039;availablefromdate&#039;, &#039;data&#039;), &#039;&amp;amp;nbsp;&#039;, false);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;availablefromgroup&#039;, &#039;availablefromenabled&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you want to put a group inside another array so that you can repeat items, use createElement instead of addGroup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* By default, groups modify the names of elements inside them by appending a number. This is often unhelpful, for example if you want to use disabledIf on the element. To prevent this behaviour, set the last parameter to false when creating a group.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems, null, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==addRule==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;elementname&#039;, get_string(&#039;error&#039;), &#039;rule type&#039;, &#039;extraruledata&#039;, &#039;server&#039;(default), false, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first param(element) is an element name and second(message) is the error message that will be displayed to the user.&lt;br /&gt;
The third parameter(type) is the type of rule. The fourth param(format) is used for extra data needed with some rules such as minlength and regex. The fifth parameter(validation) validates input data on server or client side, if validation is done on client side then it will be checked on the server side as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 * @param    string     $element       Form element name&lt;br /&gt;
 * @param    string     $message       Message to display for invalid data&lt;br /&gt;
 * @param    string     $type          Rule type, use getRegisteredRules() to get types&lt;br /&gt;
 * @param    string     $format        (optional)Required for extra rule data&lt;br /&gt;
 * @param    string     $validation    (optional)Where to perform validation: &amp;quot;server&amp;quot;, &amp;quot;client&amp;quot;&lt;br /&gt;
 * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?&lt;br /&gt;
 * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Common Rule Types&#039;&#039;&#039;&lt;br /&gt;
* required &lt;br /&gt;
* maxlength&lt;br /&gt;
* minlength&lt;br /&gt;
* rangelength&lt;br /&gt;
* email&lt;br /&gt;
* regex&lt;br /&gt;
* lettersonly&lt;br /&gt;
* alphanumeric&lt;br /&gt;
* numeric&lt;br /&gt;
* nopunctuation&lt;br /&gt;
* nonzero&lt;br /&gt;
* callback&lt;br /&gt;
* compare&lt;br /&gt;
===Server side and Client side===&lt;br /&gt;
In case you use the &#039;&#039;Client side&#039;&#039; validation option, you can mainly check for an empty or not input field. unless you write some &#039;&#039;Client side&#039;&#039; code which will probably be JavaScript functions to verify the data inside the input fields before it is submitted to the server. It could save some time if those functions are short, simple and quick to compute.&lt;br /&gt;
In case you need a more complex validation checks which relay on Moodle&#039;s internal PHP libraries (or other/external PHP libraries) you better use the &#039;&#039;Server side&#039;&#039; validation checks. Where you can query the DB, write complex PHP validation functions and much much more, that are not available (easily) when using JavaScript on the client&#039;s side.&lt;br /&gt;
==addHelpButton==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;api_key_field&#039;, &#039;api_key&#039;, &#039;block_extsearch&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The following parameters are expected:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param $elementname The name of the form element to add the help button for&lt;br /&gt;
 * @param $identifier The identifier for the help string and its title (see below)&lt;br /&gt;
 * @param $component The component name to look for the help string in&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# get_string($identifier, $component) // The title of the help page&lt;br /&gt;
# get_string(&amp;quot;{$identifier}_help&amp;quot;, $component) // The content of the help page&lt;br /&gt;
So you will need to have &#039;&#039;&#039;$identifier&#039;&#039;&#039; and &#039;&#039;&#039;{$identifier}_help&#039;&#039;&#039; defined in order for the help button to be created properly. For example the multiple choice question editing form has a button for shuffling the answers. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;shuffleanswers&#039;, &#039;shuffleanswers&#039;, &#039;qtype_multichoice&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and so the language file includes the strings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers&#039;] = &#039;Shuffle the choices?&#039;; &lt;br /&gt;
$string[&#039;shuffleanswers_help&#039;] = &#039;If enabled,.....&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also add the language string like&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers_link&#039;] = &#039;question/shuffleanswers&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to add a link to more help on Moodle docs. See [[String_API]] for more information about help icons.&lt;br /&gt;
==setDefault==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), $grades);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;grade&#039;, array(&#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), &#039;exercise&#039;));&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;grade&#039;, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Set the default of the form value with setDefault($elementname, $value); where elementname is the elementname whose default you want to set and $value is the default to set. We set the defaults for the form in definition(). This default is what is used if no data is loaded into the form with set_data(); eg. on display of the form for an &#039;add&#039; rather than &#039;update&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;desc&#039;, get_string(&#039;description&#039;));     &lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;desc&#039;, array(&#039;text&#039;=&amp;gt;$defaulttext));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that when setting the default for an editor element you must use an array to define the default &amp;quot;text&amp;quot; value as shown above.&lt;br /&gt;
==disabledIf==&lt;br /&gt;
For any element or groups of element in a form you can conditionally disable the group or individual element depending on conditions.&lt;br /&gt;
&lt;br /&gt;
You can use $mform-&amp;gt;disabledIf($elementName, $dependentOn, $condition = &#039;notchecked&#039;, $value=&#039;1&#039;)&lt;br /&gt;
* elementname can be a group. If you specify a group all elements in the group will be disabled (if dependentOn is in elementname group that is ignored and not disabled). These are the element names you&#039;ve used as the second argument in addElement or addGroup.&lt;br /&gt;
* dependentOn is the actual name of the element as it will appear in html. This can be different to the name used in addGroup particularly but also addElement where you&#039;re adding a complex element like a date_selector. Check the html of your page. You typically make the depedentOn a checkbox or select box.&lt;br /&gt;
* $condition will be &#039;notchecked&#039;, &#039;checked&#039;, &#039;noitemselected&#039;, &#039;eq&#039;, &#039;in&#039; or, if it is anything else, we test for &#039;neq&#039;.&lt;br /&gt;
** If $condition is &#039;eq&#039; or &#039;neq&#039; then we check the value of the dependentOn field and check for equality (==) or nonequality (!=) in js&lt;br /&gt;
** If $condition is &#039;checked&#039; or &#039;notchecked&#039; then we check to see if a checkbox is checked or not.&lt;br /&gt;
** If $condition is &#039;in&#039; then we check to see if a selected item is in the given list or not. (This was introduced in Moodle 2.7+)&lt;br /&gt;
** If $condition is &#039;noitemselected&#039; then we check to see whether nothing is selected in a dropdown list.&lt;br /&gt;
Examples:&lt;br /&gt;
 // Disable my control unless a checkbox is checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control if a checkbox &#039;&#039;&#039;is&#039;&#039;&#039; checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;, &#039;checked&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control when a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;eq&#039;, 42);&lt;br /&gt;
&lt;br /&gt;
 // Disable my control unless a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;neq&#039;, 42);&lt;br /&gt;
The possible choices here are in the dependency manager in lib/form/form.js.&lt;br /&gt;
===A tricky case===&lt;br /&gt;
You need to take care with disabledIf if you plan to use it with groups of checkboxes.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have a group of 5 checkboxes and you want to enable a depending item such as a drop down menu only when the first and the last checkboxes are selected.&lt;br /&gt;
&lt;br /&gt;
To fix ideas:&lt;br /&gt;
&lt;br /&gt;
If the selection in the checkboxes group is:&lt;br /&gt;
 mycheck_01 == 1&lt;br /&gt;
 mycheck_02 == 0&lt;br /&gt;
 mycheck_03 == 0&lt;br /&gt;
 mycheck_04 == 0&lt;br /&gt;
 mycheck_05 == 1&lt;br /&gt;
the depending item must be enabled while ANY OTHER COMBINATION must disable the drop down menu.&lt;br /&gt;
&lt;br /&gt;
The following code will, apparently, fail:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In fact, once you get the drop down menu enabled, you are free to unselect mycheck_01 whilst still having the depending item enabled.&lt;br /&gt;
This apparent bug occurs because a non-checked checkbox behaves like a non existing mform element. So the js code will not find the element &amp;quot;mycheck_01&amp;quot; and will not apply the corresponding rule.&lt;br /&gt;
&lt;br /&gt;
A working solution for this kind of issue seems to be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;notchecked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;notchecked&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To see a failing example as the one described, try the attachments provided in MDL-38975. See also in MDL-38975 for the working solution in action with modifications suggested by Eloy.&lt;br /&gt;
==hideIf==&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
For any element or groups of element in a form you can conditionally hide the group or individual element depending on conditions.&lt;br /&gt;
This uses the same syntax as disabledIf just with hideIf instead.&lt;br /&gt;
==setType==&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned. These should be used for get parameters such as id, course etc. which are used to load a page and also with setType(); method. Every form element should have a type specified except select, radio box and checkbox elements, these elements do a good job of cleaning themselves (only specified options are allowed as user input).&lt;br /&gt;
===Most Commonly Used PARAM_* Types===&lt;br /&gt;
These are the most commonly used PARAM_* types and their proper uses. More types can be seen in moodlelib.php starting around line 100. For the full list, see the file lib/moodlelib.php.&lt;br /&gt;
* PARAM_CLEAN is deprecated and you should try to use a more specific type.&lt;br /&gt;
* PARAM_TEXT should be used for cleaning data that is expected to contain multi-lang content. It will strip all html tags. But will still let tags for multilang support through.&lt;br /&gt;
* PARAM_NOTAGS should be used for cleaning data that is expected to be plain text. It will strip *all* html type tags. It will *not* let tags for multilang support through. This should be used for instance for email addresses where no multilang support is appropriate.&lt;br /&gt;
* PARAM_RAW means no cleaning whatsoever, it is used mostly for data from the html editor. Data from the editor is later cleaned before display using format_text() function. PARAM_RAW can also be used for data that is validated by some other way or printed by p() or s().&lt;br /&gt;
* PARAM_INT should be used for integers. PARAM_FLOAT is also available for decimal numbers but is not recommended for user input since it does not work for languages that use , as a decimal separator.&lt;br /&gt;
&lt;br /&gt;
These types are deprecated:&lt;br /&gt;
* PARAM_CLEAN obsoleted, please use a more specific type of parameter. @deprecated since 2.0&lt;br /&gt;
* PARAM_ACTION deprecated alias for PARAM_ALPHA use for various actions in forms and urls. Use PARAM_ALPHANUMEXT instead.&lt;br /&gt;
&lt;br /&gt;
==disable_form_change_checker==&lt;br /&gt;
By default, any Moodle form will pop-up an &amp;quot;Are you sure?&amp;quot; alert if you make some changes and then try to leave the page without saving. Occasionally, that is undesirable, in which case you can call&lt;br /&gt;
 $mform-&amp;gt;disable_form_change_checker()&lt;br /&gt;
&lt;br /&gt;
==RTL support==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
As of Moodle 3.2, some form elements have been refined to better support right-to-left languages. In RTL, most fields should not have their direction flipped, a URL, a path to a file, a number, ... are always displayed LTR. Input fields and text areas now will best guess whether they should be forced to be displayed in LTR based on the PARAM type associated with it. You can call:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setForceLtr(&#039;name&#039;, true/false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
on some form fields (like &#039;text&#039;) to manually set the value, and for directionality.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* [http://www.midnighthax.com/quickform.php PEAR HTML QuickForm Getting Started Guide] by Keith Edmunds of Midnighthax.com&lt;br /&gt;
* [http://pear.php.net/manual/en/package.html.html-quickform.php PEAR::HTML_QuickForm manual]&lt;br /&gt;
[[Category:Formslib]]&lt;br /&gt;
[[Category:Interfaces]]&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=64098</id>
		<title>lib/formslib.php Form Definition</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=64098"/>
		<updated>2024-04-15T09:27:04Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Use Fieldsets to group Form Elements */ Spelling&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Formslib}}&lt;br /&gt;
== &#039;&#039;definition()&#039;&#039; ==&lt;br /&gt;
The definition of the elements to be included in the form, their &#039;types&#039; (PARAM_*), helpbuttons included, etc. is all included in a function you must define in your class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;definition()&#039;&#039; is used to define the elements in the form and &#039;&#039;&#039;this definition will be used for validating data submitted as well as for printing the form.&#039;&#039;&#039; For select and checkbox type elements only data that could have been selected will be allowed. And only data that corresponds to a form element in the definition will be accepted as submitted data.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;definition()&#039;&#039; should include all elements that are going to be used on form, some elements may be removed or tweaked later in &#039;&#039;definition_after_data()&#039;&#039;. Please do not create conditional elements in &#039;&#039;definition()&#039;&#039;, the definition() should not directly depend on the submitted data.&lt;br /&gt;
&lt;br /&gt;
Note that the definition function is called when the form class is instantiated. There is no option to (say) manipulate data in the class (that may affect the rendering of the form) between instantiating the form and calling any other methods. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;libdir/formslib.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
class simplehtml_form extends moodleform {&lt;br /&gt;
&lt;br /&gt;
    function definition() {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
       &lt;br /&gt;
        $mform = $this-&amp;gt;_form; // Don&#039;t forget the underscore! &lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement()... // Add elements to your form&lt;br /&gt;
            ...&lt;br /&gt;
    }                           // Close the function&lt;br /&gt;
}                               // Close the class&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===Passing parameters to the Form===&lt;br /&gt;
The constructor for &#039;&#039;moodleform&#039;&#039; allows a number of parameters including one (&#039;&#039;$customdata&#039;&#039;) to permit an array of arbitrary data to be passed to your form. &lt;br /&gt;
&lt;br /&gt;
For example, you can pass the data &amp;quot;$email&amp;quot; and &amp;quot;$username&amp;quot; to the Form&#039;s class for use inside (say) the definition.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform_simple = new simplehtml_form( null, array(&#039;email&#039;=&amp;gt;$email, &#039;username&#039;=&amp;gt;$username ) );&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
(the first parameter is $action, &#039;&#039;null&#039;&#039; will cause the form action to be determined automatically)&lt;br /&gt;
&lt;br /&gt;
Secondly, inside the form definition you can use those parameters to set the default values to some of the form&#039;s fields&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;), &#039;maxlength=&amp;quot;100&amp;quot; size=&amp;quot;25&amp;quot; &#039;);&lt;br /&gt;
 $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);&lt;br /&gt;
 $mform-&amp;gt;addRule(&#039;email&#039;, get_string(&#039;missingemail&#039;), &#039;required&#039;, null, &#039;server&#039;);&lt;br /&gt;
 // Set default value by using a passed parameter&lt;br /&gt;
 $mform-&amp;gt;setDefault(&#039;email&#039;,$this-&amp;gt;_customdata[&#039;email&#039;]);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Use Fieldsets to group Form Elements==&lt;br /&gt;
You use code like this to open a fieldset with a &#039;&#039;legend&#039;&#039;. &amp;lt;br /&amp;gt;&lt;br /&gt;
(&#039;&#039;&#039;Note&#039;&#039;&#039;: Some themes turn off legends on admin setting pages by using CSS: &amp;lt;nowiki&amp;gt;#adminsettings legend {display:none;}&amp;lt;/nowiki&amp;gt;.)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;header&#039;, &#039;nameforyourheaderelement&#039;, get_string(&#039;titleforlegened&#039;, &#039;modulename&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can&#039;t yet nest these visible fieldsets unfortunately. But in fact groups of elements are wrapped in invisible fieldsets.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
Since Moodle 2.5 fieldsets without any required fields are collapsed by default. To display these fieldsets on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To close a fieldset on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You close a fieldset with moodle_form&#039;s closeHeaderBefore method. You tell closeHeaderBefore the element before you wish to end the fieldset. A fieldset is automatically closed if you open a new one. You need to use this code only if you want to close a fieldset and the subsequent form elements are not to be enclosed by a visible fieldset (they are still enclosed with an invisible one with no legend) :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;closeHeaderBefore(&#039;buttonar&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==addElement==&lt;br /&gt;
Use the addElement method to add an element to a form. The first few arguments are always the same. The first param is the type of the element to add. The second is the elementname to use which is normally the html name of the element in the form. The third is often the text for the label for the element.&lt;br /&gt;
&lt;br /&gt;
Some examples are below :&lt;br /&gt;
=== button ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;button&#039;, &#039;intro&#039;, get_string(&amp;quot;buttonlabel&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A button element. If you want a submit or cancel button see &#039;submit&#039; element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== autocomplete ===&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
Available since Moodle 3.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$searchareas = \core_search\manager::get_search_areas_list(true);                                                           &lt;br /&gt;
$areanames = array();                                                                                                       &lt;br /&gt;
foreach ($searchareas as $areaid =&amp;gt; $searcharea) {                                                                          &lt;br /&gt;
    $areanames[$areaid] = $searcharea-&amp;gt;get_visible_name();                                                                  &lt;br /&gt;
}                                                                                                                           &lt;br /&gt;
$options = array(                                                                                                           &lt;br /&gt;
    &#039;multiple&#039; =&amp;gt; true,                                                  &lt;br /&gt;
    &#039;noselectionstring&#039; =&amp;gt; get_string(&#039;allareas&#039;, &#039;search&#039;),                                                                &lt;br /&gt;
);         &lt;br /&gt;
$mform-&amp;gt;addElement(&#039;autocomplete&#039;, &#039;areaids&#039;, get_string(&#039;searcharea&#039;, &#039;search&#039;), $areanames, $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The autocomplete element is an advanced form element that supports server-side searching - or simple filtering of a predefined list of options. Some benefits of using this form element are that it handles very large datasets extremely well - it has great accessibility built in - and it gives a good user experience. If you have so much data you need to build pagination into a page - you could probably come up with a better design using this. The simplest way to use it is compatible with the standard &#039;select&#039; form element. You give it a list of options and some parameters to configure how it behaves. The valid parameters for this simple mode of operation are:&lt;br /&gt;
* multiple (boolean - default false) - Allow more than one selected item. The data coming from the form will be an array in this case.&lt;br /&gt;
[[image:autocomplete_multiple2.png|center|thumb|alt=autocomplete with multiple option|autocomplete with multiple option.]]&lt;br /&gt;
* noselectionstring (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to display when nothing is selected.&lt;br /&gt;
* showsuggestions (boolean - default true) - Do not show the list of suggestions when the user starts typing.&lt;br /&gt;
* placeholder (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to show in the search box when it is empty.&lt;br /&gt;
* casesensitive (boolean - default false) - Is the search case sensitive ?&lt;br /&gt;
* tags (boolean - default false) - This changes the behaviour so that the user can create new valid entries in the list by typing them and pressing enter.&lt;br /&gt;
* ajax (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - This string is the name of an AMD module that can fetch and format results.&lt;br /&gt;
* valuehtmlcallback - For use with the AJAX option, so that it can format the initial value of the form field (available since Moodle 3.5)&lt;br /&gt;
More explanation on the &#039;ajax&#039; option. This should be the name of an AMD module that implements 2 functions:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Source of data for Ajax element.&lt;br /&gt;
 *&lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.&lt;br /&gt;
 * @param {String} query The query string.                        &lt;br /&gt;
 * @param {Function} callback A callback function receiving an array of results.&lt;br /&gt;
 * @param {Function} failure A callback function to be called in case of failure, receiving the error message.&lt;br /&gt;
 * @return {Void}                                                                                                           &lt;br /&gt;
*/                                                                                                                         &lt;br /&gt;
transport: function(selector, query, callback, failure) ...&lt;br /&gt;
&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Process the results for auto complete elements.                                                                          &lt;br /&gt;
 *                                                                                                                          &lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.                                                      &lt;br /&gt;
 * @param {Array} results An array or results.                                                                              &lt;br /&gt;
 * @return {Array} New array of results.                                                                                    &lt;br /&gt;
 */                                                                                                                         &lt;br /&gt;
processResults: function(selector, results)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A good example is here: [https://github.com/moodle/moodle/blob/master/admin/tool/lp/amd/src/frameworks_datasource.js admin/tool/lp/amd/src/frameworks_datasource.js]&lt;br /&gt;
&lt;br /&gt;
The &#039;valuehtmlcallback&#039; function is needed when an AJAX-supporting form field has an initial value that needs special rendering, similar to how the AJAX code would render it when the user changes it dynamically. For example, if the field contains user ids and its initial value is &#039;1,2&#039; then you want it to use the rendered HTML display for each value (probably a user&#039;s name and picture), not just display those numbers. Here is an example, from /search/classes/output/form/search.php:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&#039;valuehtmlcallback&#039; =&amp;gt; function($value) {&lt;br /&gt;
    global $DB, $OUTPUT;&lt;br /&gt;
    $user = $DB-&amp;gt;get_record(&#039;user&#039;, [&#039;id&#039; =&amp;gt; (int)$value], &#039;*&#039;, IGNORE_MISSING);&lt;br /&gt;
    if (!$user || !user_can_view_profile($user)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
    $details = user_get_user_details($user);&lt;br /&gt;
    return $OUTPUT-&amp;gt;render_from_template(&lt;br /&gt;
        &#039;core_search/form-user-selector-suggestion&#039;, $details);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The Mustache template used here is the same as the one used by the AJAX code when the field is changed dynamically.&lt;br /&gt;
&lt;br /&gt;
When using the ajax option in an mform with validation etc - it is recommended to sub-class the php class &amp;quot;MoodleQuickForm_autocomplete&amp;quot; so that you can provide a list of name and&lt;br /&gt;
values to populate the form element if the form is re-displayed due to a validation error. An example is [https://github.com/moodle/moodle/blob/MOODLE_31_STABLE/admin/tool/lp/classes/form/framework_autocomplete.php admin/tool/lp/classes/form/framework_autocomplete.php].&lt;br /&gt;
&lt;br /&gt;
We have provided several useful subclasses of this form element already that are simple to use (course and tags).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt; &lt;br /&gt;
    // Course example.&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;multiple&#039; - boolean multi select                                                                      &lt;br /&gt;
    //                       &#039;exclude&#039; - array or int, list of course ids to never show                                             &lt;br /&gt;
    //                       &#039;requiredcapabilities&#039; - array of capabilities. Uses ANY to combine them.                              &lt;br /&gt;
    //                       &#039;limittoenrolled&#039; - boolean Limits to enrolled courses.                                                &lt;br /&gt;
    //                       &#039;includefrontpage&#039; - boolean Enables the frontpage to be selected.  &lt;br /&gt;
    $options = array(&#039;multiple&#039; =&amp;gt; true, &#039;includefrontpage&#039; =&amp;gt; true);                                                           &lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course&#039;, &#039;mappedcourses&#039;, get_string(&#039;courses&#039;), $options); &lt;br /&gt;
&lt;br /&gt;
    // Tags&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;showstandard&#039; - boolean One of the core_tag_tag constants to say which tags to display&lt;br /&gt;
    //                       &#039;component&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    //                       &#039;itemtype&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;tags&#039;, &#039;interests&#039;, get_string(&#039;interestslist&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;user&#039;, &#039;component&#039; =&amp;gt; &#039;core&#039;));     &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== checkbox ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a simple checkbox. The third parameter for this element is the label to display on the left side of the form. You can also supply a string as a fourth parameter to specify a label that will appear on the right of the element. Checkboxes and radio buttons can be grouped and have individual labels on their right.&lt;br /&gt;
&lt;br /&gt;
You can have a 5th parameter $attributes, as on other elements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BEWARE:&#039;&#039;&#039; Unchecked checkboxes return nothing at all (as if they didn&#039;t exist). This can surprise the unwary. You may wish to use advcheckbox instead, which does return a value when not checked. &#039;Advcheckbox&#039; eliminates this problem. &lt;br /&gt;
==== advcheckbox ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;), &#039;Label displayed after checkbox&#039;, array(&#039;group&#039; =&amp;gt; 1), array(0, 1));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Similar to the checkbox above, but with some important improvements:&lt;br /&gt;
# The (optional) 5th parameter is a normal $attributes array, normally used to set HTML attributes for the &amp;lt;input&amp;gt; element. However, a special value of &#039;group&#039; can be given, which will add a class name to the element, and enable its grouping for a [[lib/formslib.php_add_checkbox_controller|checkbox controller]]&lt;br /&gt;
#The (optional) 6th parameter is an array of values that will be associated with the checked/unchecked state of the checkbox. With a normal checkbox you cannot choose that value, and in fact an unchecked checkbox will not even be sent with the form data.&lt;br /&gt;
#It returns a 0 value when unchecked. Compare with the ordinary checkbox which does not return anything at all.&lt;br /&gt;
=== choosecoursefile ===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;choosecoursefile&#039;, &#039;mediafile&#039;, get_string(&#039;mediafile&#039;, &#039;lesson&#039;), array(&#039;courseid&#039;=&amp;gt;$COURSE-&amp;gt;id));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Choose a file from the course files area. The fourth option is a list of options for the element. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: This has been superceded by [[#filepicker|filepicker]] in Moodle 2.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&#039;courseid&#039; =&amp;gt;null,  //if it is null (default then use global $COURSE&lt;br /&gt;
      &#039;height&#039;   =&amp;gt;500,   // height of the popup window&lt;br /&gt;
      &#039;width&#039;    =&amp;gt;750,   // width of the popup window&lt;br /&gt;
      &#039;options&#039;  =&amp;gt;&#039;none&#039;); //options string for the pop up window &lt;br /&gt;
                          //eg. &#039;menubar=0,location=0,scrollbars,resizable&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;maxlength&#039; =&amp;gt; 255, &#039;size&#039; =&amp;gt; 48)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the maxlength / size of the text box (note size will default to 48 if not specified)&lt;br /&gt;
&lt;br /&gt;
Finally, as this element is a group containing two elements (button + value), you can add validation rules by using the &#039;&#039;&#039;addGroupRule()&#039;&#039;&#039; method in this (complex) way:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;elementname&#039;, array(&#039;value&#039; =&amp;gt; array(array(list, of, rule, params, but, fieldname))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Where: &#039;&#039;&#039;&amp;quot;elementname&amp;quot;&#039;&#039;&#039; is the name of the choosecoursefile group element, &#039;&#039;&#039;&amp;quot;value&amp;quot;&#039;&#039;&#039; is the name of the text field within the group and the &#039;&#039;&#039;&amp;quot;list, of, addrule, params, but, fieldname&amp;quot;&#039;&#039;&#039; is exactly that, the list of fields in the normal addRule() function but ommiting the first one, the fieldname.&lt;br /&gt;
&lt;br /&gt;
For example, the [http://cvs.moodle.org/moodle/mod/resource/type/file/resource.class.php?view=markup file/url resource type], uses one &amp;quot;choosecoursefile&amp;quot; element, and it controls the maximum length of the field (255) with this use of addGroupRule():&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;reference&#039;, array(&#039;value&#039; =&amp;gt; array(array(get_string(&#039;maximumchars&#039;, &#039;&#039;, 255), &#039;maxlength&#039;, 255, &#039;client&#039;))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== date_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_selector&#039;, &#039;assesstimefinish&#039;, get_string(&#039;to&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a date selector. You can select a Day, Month and Year using a group of select boxes. The fourth param here is an array of options. The defaults for the options are :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;optional&#039;  =&amp;gt; false&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. You can supply a fifth param of attributes here as well.&lt;br /&gt;
=== date_time_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_time_selector&#039;, &#039;assesstimestart&#039;, get_string(&#039;from&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a group of select boxes to select a date (Day Month and Year) and time (Hour and Minute). When submitted, submitted data is processed and a timestamp is passed to $form-&amp;gt;get_data(); the fourth param here is an array of options. The defaults for the options are:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;step&#039;      =&amp;gt; 5,&lt;br /&gt;
    &#039;optional&#039; =&amp;gt; false,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. Setting &#039;optional&#039; to true adds an &#039;enable&#039; checkbox to the selector. You can supply a fifth param of attributes here as well.&lt;br /&gt;
===duration===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;duration&#039;, &#039;timelimit&#039;, get_string(&#039;timelimit&#039;, &#039;quiz&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This field type lets the user input an interval of time. It comprises a text field, where you can type a number, and a dropdown for selecting a unit (days, hours, minutes or seconds). When submitted the value is converted to a number of seconds.&lt;br /&gt;
&lt;br /&gt;
You can add a fourth parameter to give options. At the moment the only option supported is here is an array of options. The defaults for the options is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;optional&#039; =&amp;gt; true)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;size&#039; =&amp;gt; 5)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the size of the text box.&lt;br /&gt;
=== editor ===&lt;br /&gt;
This replaces the old htmleditor field type. It allows the user to enter rich text content in a variety of formats.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;fieldname&#039;, get_string(&#039;labeltext&#039;, &#039;langfile&#039;));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;fieldname&#039;, PARAM_RAW);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
NOTE: It won&#039;t work properly without the setType() as shown.&lt;br /&gt;
&lt;br /&gt;
If you would like to let the user use the filepicker to upload images etc. that are used in the content, then see [[Using_the_File_API_in_Moodle_forms]].&lt;br /&gt;
&lt;br /&gt;
You can supply a fifth param to htmleditor of an array of options that are mostly related to file handling:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;subdirs&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxbytes&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxfiles&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;changeformat&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;context&#039;=&amp;gt;null,&lt;br /&gt;
    &#039;noclean&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;trusttext&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;enable_filemanagement&#039; =&amp;gt; true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The option &#039;enable_filemanagement&#039; will display the file management button on true and remove it on false.&lt;br /&gt;
&lt;br /&gt;
To save the data if you don&#039;t care about files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$text     = $formdata-&amp;gt;fieldname[&#039;text&#039;];&lt;br /&gt;
$format   = $formdata-&amp;gt;fieldname[&#039;format&#039;];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: Because the text editor might be &amp;quot;Atto&amp;quot; (depending on user preferences) and Atto has an &amp;quot;autosave&amp;quot; feature - it requires that the combination of $PAGE-&amp;gt;url and this elementid are unique. If not, the autosaved text for a different form may be restored into this form.&lt;br /&gt;
=== file ===&lt;br /&gt;
File upload input box with browse button. In the form definition type&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
after form submission and validation use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If there is no requirement to save the file, you can read the file contents directly into a string as follows...&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    $mform-&amp;gt;get_file_content(&#039;attachment&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you need advanced settings such as required file, different max upload size or name of uploaded file&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0, true, true, false));&lt;br /&gt;
            $mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
            $mform-&amp;gt;addRule(&#039;attachment&#039;, null, &#039;required&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
    $newfilename = $mform-&amp;gt;get_new_filename();&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When porting old code it is also possible to use the upload manager directly for processing of uploaded files.&lt;br /&gt;
&lt;br /&gt;
Please note that if using set_upload_manager() it must be before addElement(&#039;file&#039;,..).&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
File uploading was rewritten in 2.0. Please see inline docs for now. This page will be updated when the new API stabilises.&lt;br /&gt;
===filepicker===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
General replacement of &#039;&#039;file&#039;&#039; element.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null, array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See also [[Using the File API in Moodle forms]]&lt;br /&gt;
=== hidden ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;hidden&#039;, &#039;reply&#039;, &#039;yes&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A hidden element. Set the element name (in this case &#039;&#039;&#039;reply&#039;&#039;&#039;) to the stated value (in this case &#039;&#039;&#039;yes&#039;&#039;&#039;).&lt;br /&gt;
=== html ===&lt;br /&gt;
You can add arbitrary HTML to your Moodle form:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;html&#039;, &#039;&amp;lt;div class=&amp;quot;qheader&amp;quot;&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See [http://moodle.org/mod/forum/discuss.php?d=126935 &amp;quot;Question: Can I put a moodleform inside a table td?&amp;quot;] for a concrete example.&lt;br /&gt;
=== htmleditor &amp;amp; format ===&lt;br /&gt;
These elements are now deprecated. Please use the [[#editor|editor]] field type instead.&lt;br /&gt;
===modgrade===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modgrade&#039;, &#039;scale&#039;, get_string(&#039;grade&#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade for any activity module. The fourth argument is whether to include an option for no grade which has a value 0. This select box does include scales. The default is true, include no grade option.&lt;br /&gt;
&lt;br /&gt;
A helpbutton is automatically added.&lt;br /&gt;
===modvisible===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modvisible&#039;, &#039;visible&#039;, get_string(&#039;visible&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade visibility in an activity mod update form.&lt;br /&gt;
===password===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;password&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element. Fourth param is an array or string of attributes.&lt;br /&gt;
===passwordunmask===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;passwordunmask&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element with option to show the password in plaintext. Fourth param is an array or string of attributes.&lt;br /&gt;
=== radio ===&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$radioarray=array();&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;yes&#039;), 1, $attributes);&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;no&#039;), 0, $attributes);&lt;br /&gt;
$mform-&amp;gt;addGroup($radioarray, &#039;radioar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Second param names the radio button and should be the same for each button in the group in order to toggle correctly. Third param would be the label for the form element but is generally ignored as this element will always be in a group which has it&#039;s own label. Fourth param is a string, a label to be displayed on the right of the element. The fifth is the value for this radio button. $attributes can be a string or an array of attributes.&lt;br /&gt;
&lt;br /&gt;
It is possible to add help to individual radio buttons but this requires a custom template to be defined for the group elements. See MDL-15571.&lt;br /&gt;
&lt;br /&gt;
Since 2.3 it cannot be statically called anymore, so we need to call createElement from $mform reference.&lt;br /&gt;
==== setDefault ====&lt;br /&gt;
To set the default for a radio button group as above use the following :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;yesno&#039;, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This would make the default &#039;no&#039;.&lt;br /&gt;
===select===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;type&#039;, get_string(&#039;forumtype&#039;, &#039;forum&#039;), $FORUM_TYPES, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The fourth param for this element is an array of options for the select box. The keys are the values for the option and the value of the array is the text for the option. The fifth param $attributes is optional, see text element for description of attributes param.&lt;br /&gt;
&lt;br /&gt;
It is also possible to create a select with certain options disabled, using [http://stackoverflow.com/questions/2138089/how-can-i-use-quickform-to-add-disabled-select-options/2150275#2150275 this technique].&lt;br /&gt;
&lt;br /&gt;
You can set an &#039;onchange&#039; attribute when adding or creating the select element: &lt;br /&gt;
&lt;br /&gt;
$form-&amp;gt;addElement(&#039;select&#039;, &#039;iselTest&#039;, &#039;Test Select:&#039;, $arrayOfOptions, array(&#039;onchange&#039; =&amp;gt; &#039;javascript:myFunctionToDoSomething();&#039;));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====multi-select====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), array(&#039;red&#039;, &#039;blue&#039;, &#039;green&#039;), $attributes);&lt;br /&gt;
$select-&amp;gt;setMultiple(true);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====setSelected=====&lt;br /&gt;
To set the default selected item in a select element, you can use the &#039;setSelected&#039; method. The &#039;setSelected&#039; can either get a value or an array of values.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array(&lt;br /&gt;
    &#039;ff0000&#039; =&amp;gt; &#039;Red&#039;,&lt;br /&gt;
    &#039;00ff00&#039; =&amp;gt; &#039;Green&#039;,&lt;br /&gt;
    &#039;0000ff&#039; =&amp;gt; &#039;Blue&#039;&lt;br /&gt;
);&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), $options);&lt;br /&gt;
// This will select the colour blue.&lt;br /&gt;
$select-&amp;gt;setSelected(&#039;0000ff&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or for multiple-selection:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$skillsarray = array(&lt;br /&gt;
    &#039;val1&#039; =&amp;gt; &#039;Skill A&#039;,&lt;br /&gt;
    &#039;val2&#039; =&amp;gt; &#039;Skill B&#039;,&lt;br /&gt;
    &#039;val3&#039; =&amp;gt; &#039;Skill C&#039;&lt;br /&gt;
);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;md_skills&#039;, get_string(&#039;skills&#039;, &#039;metadata&#039;), $skillsarray);&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setMultiple(true);&lt;br /&gt;
// This will select the skills A and B.&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setSelected(array(&#039;val1&#039;, &#039;val2&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
However you probably don&#039;t want to do this. Instead you probably want to use setDefault, or set it using the form&#039;s setData method.&lt;br /&gt;
===selectyesno===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;maxbytes&#039;, get_string(&#039;maxattachmentsize&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you want a yes / no select box this one automatically translates itself and has value 1 for yes and 0 for no.&lt;br /&gt;
===selectwithlink===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array();&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectwithlink&#039;, &#039;scaleid&#039;, get_string(&#039;scale&#039;), $options, null, &lt;br /&gt;
    array(&#039;link&#039; =&amp;gt; $CFG-&amp;gt;wwwroot.&#039;/grade/edit/scale/edit.php?courseid=&#039;.$COURSE-&amp;gt;id, &#039;label&#039; =&amp;gt; get_string(&#039;scalescustomcreate&#039;)));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
select type element with options containing link&lt;br /&gt;
===static===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;description&#039;, &#039;exercise&#039;),&lt;br /&gt;
    get_string(&#039;descriptionofexercise&#039;, &#039;exercise&#039;, $COURSE-&amp;gt;students));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a static element. It should be used with care if it is used to display a static piece of text with a label. The third param is the label and the fourth is the static text itself.&lt;br /&gt;
===submit, reset and cancel===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//normally you use add_action_buttons instead of this code&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;reset&#039;, &#039;resetbutton&#039;, get_string(&#039;revert&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;cancel&#039;);&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, &#039; &#039;, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A &#039;Submit&#039; type element is a submit type form element which will submit the form. A &#039;Reset&#039; will not submit the form but will reset any changes the user has made to form contents. A &#039;Cancel&#039; element cancels form submission. You need to have a branch in your code before you check for get_data() to check if submission has been cancelled with is_cancelled(); See the example on the usage page.&lt;br /&gt;
&lt;br /&gt;
You should name your submit and reset buttons &#039;submitbutton&#039; and &#039;resetbutton&#039; or something similar (not &#039;submit&#039; and &#039;reset&#039;). This avoids problems in JavaScript of collisions between form element names and names of JavaScript methods of the form object.&lt;br /&gt;
====add_action_buttons($cancel = true, $submitlabel=null);====&lt;br /&gt;
You will normally use this helper function which is a method of moodleform to add all the &#039;action&#039; buttons to the end of your form. A boolean parameter allow you to specify whether to include a cancel button and specify the label for your submit button (pass the result of get_string). Default for the submit button label is get_string(&#039;savechanges&#039;). Note the &#039;&#039;&#039;$this&#039;&#039;&#039; not &#039;&#039;&#039;$mform&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===text===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;name&#039;, get_string(&#039;forumname&#039;, &#039;forum&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For a simple text input element. (For text labels, use the &#039;static&#039; element.) Your fourth parameter here can be a string or array of attributes for the text element. The following are equivalent :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$attributes=&#039;size=&amp;quot;20&amp;quot;&#039;;&lt;br /&gt;
$attributes=array(&#039;size&#039;=&amp;gt;&#039;20&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Generally you are encouraged to use CSS instead of using attributes for styling.&lt;br /&gt;
&lt;br /&gt;
===float===&lt;br /&gt;
{{Moodle 3.7}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;float&#039;, &#039;defaultmark&#039;, get_string(&#039;defaultmark&#039;, &#039;question&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use the float element if you want a text box to get a floating point number. This element automatically supports localised decimal separators. You don&#039;t need to use setType with the float element.&lt;br /&gt;
&lt;br /&gt;
===textarea===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;textarea&#039;, &#039;introduction&#039;, get_string(&amp;quot;introtext&amp;quot;, &amp;quot;survey&amp;quot;), &#039;wrap=&amp;quot;virtual&amp;quot; rows=&amp;quot;20&amp;quot; cols=&amp;quot;50&amp;quot;&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A textarea element. If you want an htmleditor use htmleditor element. Fourth element here is a string or array of attributes.&lt;br /&gt;
===recaptcha===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;recaptcha&#039;, &#039;recaptcha_field_name&#039;, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use this recaptcha element to reduce the spam risk in your forms. Third element here is a string or array of attributes. Take care to get an API key from http://recaptcha.net/api/getkey before using this element.&lt;br /&gt;
&lt;br /&gt;
To check whether recaptcha is enabled at site level use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (!empty($CFG-&amp;gt;recaptchapublickey) &amp;amp;&amp;amp; !empty($CFG-&amp;gt;recaptchaprivatekey)) {&lt;br /&gt;
    //recaptcha is enabled&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===tags===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;field_name&#039;, $lable, $options, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Used for editing a list of tags, for example on a blog post.&lt;br /&gt;
&lt;br /&gt;
There is only one option available, &#039;display&#039;, which should be set to one of the contstants MoodleQuickForm_tags::ONLYOFFICIAL, NOOFFICIAL or DEFAULTUI. This controls whether the official tags are listed for easy selection, or a text area where arbitrary tags may be typed, or both. The default is both.&lt;br /&gt;
&lt;br /&gt;
The value should be set/returned as an array of tags.&lt;br /&gt;
===grading===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;grading&#039;, &#039;advancedgrading&#039;, get_string(&#039;grade&#039;).&#039;:&#039;, array(&#039;gradinginstance&#039; =&amp;gt; $gradinginstance));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Custom element for advanced grading plugins.&lt;br /&gt;
&lt;br /&gt;
When adding the &#039;grading&#039; element to the form, developer must pass an object of class gradingform_instance as $attributes[&#039;gradinginstance&#039;]. Otherwise an exception will be thrown.&lt;br /&gt;
===questioncategory===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;questioncategory&#039;, &#039;category&#039;, get_string(&#039;category&#039;, &#039;question&#039;),&lt;br /&gt;
    array(&#039;contexts&#039;=&amp;gt;$contexts, &#039;top&#039;=&amp;gt;true, &#039;currentcat&#039;=&amp;gt;$currentcat, &#039;nochildrenof&#039;=&amp;gt;$currentcat));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates a drop down element to select a question category.&lt;br /&gt;
&lt;br /&gt;
Options are:&lt;br /&gt;
&#039;&#039;&#039;contexts&#039;&#039;&#039; - (required) context in which question appears&lt;br /&gt;
&#039;&#039;&#039;currentcat&#039;&#039;&#039; - (optional) course category&lt;br /&gt;
&#039;&#039;&#039;top&#039;&#039;&#039; - (optional) if true will put top categories on top&lt;br /&gt;
&#039;&#039;&#039;nochildrenof&#039;&#039;&#039; - (optional) Format categories into an indented list reflecting the tree structure&lt;br /&gt;
=== filetypes ===&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
Available since Moodle 3.4&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;allowedfiletypes&#039;, get_string(&#039;allowedfiletypes&#039;, &#039;tool_myplugin&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates an input element allowing the user to specify file types for the given purpose. The typical scenario is a setting that allows the teacher define a list of allowed file types submitted by students.&lt;br /&gt;
&lt;br /&gt;
The element allows the user to either type the list of filetypes manually, or select the types from the list. Also supported is selecting the whole group of file types - such as &amp;quot;image&amp;quot;. The element integrates with the [[Core filetypes]] system so all default types and groups are presented, as well as those [[:en:Working with files#Site administration settings|defined locally by the admin]].&lt;br /&gt;
&lt;br /&gt;
As the list can be types in manually, the form processing code should always normalize it first via the provided utility methods:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$allowedfiletypes = $filetypesutil-&amp;gt;normalize_file_types($formdata-&amp;gt;allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This always returns an array of recognized valid values. The original list can be separated by whitespace, end of lines, commas, colons and semicolons. During the normalization, values are converted to lowercase, empty valies and duplicates are removed. Glob evaluation is not supported.&lt;br /&gt;
&lt;br /&gt;
The normalization should also happen if the previously defined list had been saved to the database and re-read for actual usage. The normalization output value can be directly used as the accepted_types option for the filepicker.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$options[&#039;accepted_types&#039;] = $filetypesutil-&amp;gt;normalize_file_types($allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
By default, user input is validated against the list of known file types and groups. This validation can be disabled via options.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Supported options&#039;&#039;&#039;&lt;br /&gt;
; onlytypes : Allow selection from these file types only; for example [&#039;onlytypes&#039; =&amp;gt; [&#039;web_image&#039;]].&lt;br /&gt;
; allowall : Allow to select &#039;All file types&#039;, defaults to true. Does not apply with onlytypes are set.&lt;br /&gt;
; allowunknown : Skip implicit validation against the list of known file types.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;doctypes&#039;, get_string(&#039;doctypes&#039;, &#039;tool_myplugin&#039;), [&#039;onlytypes&#039; =&amp;gt; [&#039;document&#039;], &#039;allowunknown&#039; =&amp;gt; true]);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==addGroup==&lt;br /&gt;
A &#039;group&#039; in formslib is just a group of elements that will have a label and will be included on one line. &lt;br /&gt;
&lt;br /&gt;
For example typical code to include a submit and cancel button on the same line : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;cancel&#039;, get_string(&#039;cancel&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You use the same arguments for createElement as you do for addElement. Any label for the element in the third argument is normally ignored (but not in the case of the submit buttons above where the third argument is not for a label but is the text for the button).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a bad example (don&#039;t do this for real, use the &#039;optional&#039; =&amp;gt; true option of the date element): putting a date_selector (which is itself a group of elements) and a checkbox on the same line, note that you can disable every element in the group using the group name &#039;availablefromgroup&#039; but it doesn&#039;t disable the controlling element the &#039;availablefromenabled&#039; checkbox:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$availablefromgroup=array();&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;date_selector&#039;, &#039;availablefrom&#039;, &#039;&#039;);&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;availablefromenabled&#039;, &#039;&#039;, get_string(&#039;enable&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($availablefromgroup, &#039;availablefromgroup&#039;, get_string(&#039;availablefromdate&#039;, &#039;data&#039;), &#039;&amp;amp;nbsp;&#039;, false);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;availablefromgroup&#039;, &#039;availablefromenabled&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you want to put a group inside another array so that you can repeat items, use createElement instead of addGroup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* By default, groups modify the names of elements inside them by appending a number. This is often unhelpful, for example if you want to use disabledIf on the element. To prevent this behaviour, set the last parameter to false when creating a group.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems, null, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==addRule==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;elementname&#039;, get_string(&#039;error&#039;), &#039;rule type&#039;, &#039;extraruledata&#039;, &#039;server&#039;(default), false, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first param(element) is an element name and second(message) is the error message that will be displayed to the user.&lt;br /&gt;
The third parameter(type) is the type of rule. The fourth param(format) is used for extra data needed with some rules such as minlength and regex. The fifth parameter(validation) validates input data on server or client side, if validation is done on client side then it will be checked on the server side as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 * @param    string     $element       Form element name&lt;br /&gt;
 * @param    string     $message       Message to display for invalid data&lt;br /&gt;
 * @param    string     $type          Rule type, use getRegisteredRules() to get types&lt;br /&gt;
 * @param    string     $format        (optional)Required for extra rule data&lt;br /&gt;
 * @param    string     $validation    (optional)Where to perform validation: &amp;quot;server&amp;quot;, &amp;quot;client&amp;quot;&lt;br /&gt;
 * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?&lt;br /&gt;
 * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Common Rule Types&#039;&#039;&#039;&lt;br /&gt;
* required &lt;br /&gt;
* maxlength&lt;br /&gt;
* minlength&lt;br /&gt;
* rangelength&lt;br /&gt;
* email&lt;br /&gt;
* regex&lt;br /&gt;
* lettersonly&lt;br /&gt;
* alphanumeric&lt;br /&gt;
* numeric&lt;br /&gt;
* nopunctuation&lt;br /&gt;
* nonzero&lt;br /&gt;
* callback&lt;br /&gt;
* compare&lt;br /&gt;
===Server side and Client side===&lt;br /&gt;
In case you use the &#039;&#039;Client side&#039;&#039; validation option, you can mainly check for an empty or not input field. unless you write some &#039;&#039;Client side&#039;&#039; code which will probably be JavaScript functions to verify the data inside the input fields before it is submitted to the server. It could save some time if those functions are short, simple and quick to compute.&lt;br /&gt;
In case you need a more complex validation checks which relay on Moodle&#039;s internal PHP libraries (or other/external PHP libraries) you better use the &#039;&#039;Server side&#039;&#039; validation checks. Where you can query the DB, write complex PHP validation functions and much much more, that are not available (easily) when using JavaScript on the client&#039;s side.&lt;br /&gt;
==addHelpButton==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;api_key_field&#039;, &#039;api_key&#039;, &#039;block_extsearch&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The following parameters are expected:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param $elementname The name of the form element to add the help button for&lt;br /&gt;
 * @param $identifier The identifier for the help string and its title (see below)&lt;br /&gt;
 * @param $component The component name to look for the help string in&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# get_string($identifier, $component) // The title of the help page&lt;br /&gt;
# get_string(&amp;quot;{$identifier}_help&amp;quot;, $component) // The content of the help page&lt;br /&gt;
So you will need to have &#039;&#039;&#039;$identifier&#039;&#039;&#039; and &#039;&#039;&#039;{$identifier}_help&#039;&#039;&#039; defined in order for the help button to be created properly. For example the multiple choice question editing form has a button for shuffling the answers. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;shuffleanswers&#039;, &#039;shuffleanswers&#039;, &#039;qtype_multichoice&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and so the language file includes the strings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers&#039;] = &#039;Shuffle the choices?&#039;; &lt;br /&gt;
$string[&#039;shuffleanswers_help&#039;] = &#039;If enabled,.....&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also add the language string like&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers_link&#039;] = &#039;question/shuffleanswers&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to add a link to more help on Moodle docs. See [[String_API]] for more information about help icons.&lt;br /&gt;
==setDefault==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), $grades);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;grade&#039;, array(&#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), &#039;exercise&#039;));&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;grade&#039;, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Set the default of the form value with setDefault($elementname, $value); where elementname is the elementname whose default you want to set and $value is the default to set. We set the defaults for the form in definition(). This default is what is used if no data is loaded into the form with set_data(); eg. on display of the form for an &#039;add&#039; rather than &#039;update&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;desc&#039;, get_string(&#039;description&#039;));     &lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;desc&#039;, array(&#039;text&#039;=&amp;gt;$defaulttext));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that when setting the default for an editor element you must use an array to define the default &amp;quot;text&amp;quot; value as shown above.&lt;br /&gt;
==disabledIf==&lt;br /&gt;
For any element or groups of element in a form you can conditionally disable the group or individual element depending on conditions.&lt;br /&gt;
&lt;br /&gt;
You can use $mform-&amp;gt;disabledIf($elementName, $dependentOn, $condition = &#039;notchecked&#039;, $value=&#039;1&#039;)&lt;br /&gt;
* elementname can be a group. If you specify a group all elements in the group will be disabled (if dependentOn is in elementname group that is ignored and not disabled). These are the element names you&#039;ve used as the second argument in addElement or addGroup.&lt;br /&gt;
* dependentOn is the actual name of the element as it will appear in html. This can be different to the name used in addGroup particularly but also addElement where you&#039;re adding a complex element like a date_selector. Check the html of your page. You typically make the depedentOn a checkbox or select box.&lt;br /&gt;
* $condition will be &#039;notchecked&#039;, &#039;checked&#039;, &#039;noitemselected&#039;, &#039;eq&#039;, &#039;in&#039; or, if it is anything else, we test for &#039;neq&#039;.&lt;br /&gt;
** If $condition is &#039;eq&#039; or &#039;neq&#039; then we check the value of the dependentOn field and check for equality (==) or nonequality (!=) in js&lt;br /&gt;
** If $condition is &#039;checked&#039; or &#039;notchecked&#039; then we check to see if a checkbox is checked or not.&lt;br /&gt;
** If $condition is &#039;in&#039; then we check to see if a selected item is in the given list or not. (This was introduced in Moodle 2.7+)&lt;br /&gt;
** If $condition is &#039;noitemselected&#039; then we check to see whether nothing is selected in a dropdown list.&lt;br /&gt;
Examples:&lt;br /&gt;
 // Disable my control unless a checkbox is checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control if a checkbox &#039;&#039;&#039;is&#039;&#039;&#039; checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;, &#039;checked&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control when a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;eq&#039;, 42);&lt;br /&gt;
&lt;br /&gt;
 // Disable my control unless a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;neq&#039;, 42);&lt;br /&gt;
The possible choices here are in the dependency manager in lib/form/form.js.&lt;br /&gt;
===A tricky case===&lt;br /&gt;
You need to take care with disabledIf if you plan to use it with groups of checkboxes.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have a group of 5 checkboxes and you want to enable a depending item such as a drop down menu only when the first and the last checkboxes are selected.&lt;br /&gt;
&lt;br /&gt;
To fix ideas:&lt;br /&gt;
&lt;br /&gt;
If the selection in the checkboxes group is:&lt;br /&gt;
 mycheck_01 == 1&lt;br /&gt;
 mycheck_02 == 0&lt;br /&gt;
 mycheck_03 == 0&lt;br /&gt;
 mycheck_04 == 0&lt;br /&gt;
 mycheck_05 == 1&lt;br /&gt;
the depending item must be enabled while ANY OTHER COMBINATION must disable the drop down menu.&lt;br /&gt;
&lt;br /&gt;
The following code will, apparently, fail:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In fact, once you get the drop down menu enabled, you are free to unselect mycheck_01 whilst still having the depending item enabled.&lt;br /&gt;
This apparent bug occurs because a non-checked checkbox behaves like a non existing mform element. So the js code will not find the element &amp;quot;mycheck_01&amp;quot; and will not apply the corresponding rule.&lt;br /&gt;
&lt;br /&gt;
A working solution for this kind of issue seems to be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;notchecked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;notchecked&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To see a failing example as the one described, try the attachments provided in MDL-38975. See also in MDL-38975 for the working solution in action with modifications suggested by Eloy.&lt;br /&gt;
==hideIf==&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
For any element or groups of element in a form you can conditionally hide the group or individual element depending on conditions.&lt;br /&gt;
This uses the same syntax as disabledIf just with hideIf instead.&lt;br /&gt;
==setType==&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned. These should be used for get parameters such as id, course etc. which are used to load a page and also with setType(); method. Every form element should have a type specified except select, radio box and checkbox elements, these elements do a good job of cleaning themselves (only specified options are allowed as user input).&lt;br /&gt;
===Most Commonly Used PARAM_* Types===&lt;br /&gt;
These are the most commonly used PARAM_* types and their proper uses. More types can be seen in moodlelib.php starting around line 100. For the full list, see the file lib/moodlelib.php.&lt;br /&gt;
* PARAM_CLEAN is deprecated and you should try to use a more specific type.&lt;br /&gt;
* PARAM_TEXT should be used for cleaning data that is expected to contain multi-lang content. It will strip all html tags. But will still let tags for multilang support through.&lt;br /&gt;
* PARAM_NOTAGS should be used for cleaning data that is expected to be plain text. It will strip *all* html type tags. It will *not* let tags for multilang support through. This should be used for instance for email addresses where no multilang support is appropriate.&lt;br /&gt;
* PARAM_RAW means no cleaning whatsoever, it is used mostly for data from the html editor. Data from the editor is later cleaned before display using format_text() function. PARAM_RAW can also be used for data that is validated by some other way or printed by p() or s().&lt;br /&gt;
* PARAM_INT should be used for integers. PARAM_FLOAT is also available for decimal numbers but is not recommended for user input since it does not work for languages that use , as a decimal separator.&lt;br /&gt;
&lt;br /&gt;
These types are deprecated:&lt;br /&gt;
* PARAM_CLEAN obsoleted, please use a more specific type of parameter. @deprecated since 2.0&lt;br /&gt;
* PARAM_ACTION deprecated alias for PARAM_ALPHA use for various actions in forms and urls. Use PARAM_ALPHANUMEXT instead.&lt;br /&gt;
&lt;br /&gt;
==disable_form_change_checker==&lt;br /&gt;
By default, any Moodle form will pop-up an &amp;quot;Are you sure?&amp;quot; alert if you make some changes and then try to leave the page without saving. Occasionally, that is undesirable, in which case you can call&lt;br /&gt;
 $mform-&amp;gt;disable_form_change_checker()&lt;br /&gt;
&lt;br /&gt;
==RTL support==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
As of Moodle 3.2, some form elements have been refined to better support right-to-left languages. In RTL, most fields should not have their direction flipped, a URL, a path to a file, a number, ... are always displayed LTR. Input fields and text areas now will best guess whether they should be forced to be displayed in LTR based on the PARAM type associated with it. You can call:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setForceLtr(&#039;name&#039;, true/false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
on some form fields (like &#039;text&#039;) to manually set the value, and for directionality.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* [http://www.midnighthax.com/quickform.php PEAR HTML QuickForm Getting Started Guide] by Keith Edmunds of Midnighthax.com&lt;br /&gt;
* [http://pear.php.net/manual/en/package.html.html-quickform.php PEAR::HTML_QuickForm manual]&lt;br /&gt;
[[Category:Formslib]]&lt;br /&gt;
[[Category:Interfaces]]&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Gradebook_API&amp;diff=63947</id>
		<title>Gradebook API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Gradebook_API&amp;diff=63947"/>
		<updated>2023-07-23T10:50:18Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: Add Warning and Update templates as mod_assignment was removed in Moodle 4.2&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Update}}&lt;br /&gt;
{{Warning|This page uses obsolete plugin mod_assignment for some examples, this plugin was removed in Moodle 4.2 (MDL-72350).}}&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
This document explains how custom Moodle activity modules may use the Gradebook API to read and write student grades.&lt;br /&gt;
&lt;br /&gt;
The Gradebook API allows you to read and write from the gradebook and to provide an interface for detailed grading information.&lt;br /&gt;
&lt;br /&gt;
==File Locations==&lt;br /&gt;
&lt;br /&gt;
The main file for the gradebook API is /lib/gradelib.php&lt;br /&gt;
&lt;br /&gt;
The grade item classes like grade_item, grade_category and grade_grade (a single student&#039;s grade) are in /lib/grade/.&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
&lt;br /&gt;
grade_update() is used to submit new or updated grades.&lt;br /&gt;
&lt;br /&gt;
grade_get_grades() is used to retrieve grade information about a given activity. Optionally you can retrieve student grades for that activity.&lt;br /&gt;
&lt;br /&gt;
grade_update_outcomes() is used to submit new or updated outcome based grades. Here is a document describing [https://docs.moodle.org/en/Outcomes how Moodle outcomes work] from a user perspective.&lt;br /&gt;
&lt;br /&gt;
==Things to Implement==&lt;br /&gt;
&lt;br /&gt;
===Gradebook redirection page===&lt;br /&gt;
&lt;br /&gt;
This should be at /mod/$modname/grade.php. For example the assignment activity module&#039;s gradebook redirection page is at /mod/assignment/grade.php.&lt;br /&gt;
&lt;br /&gt;
A teacher or student clicking on the activity name in the gradebook is sent to grade.php within the activity. It should redirect the user to the appropriate page. For example, it could send students to the activity itself while sending teachers to a list of participating students.&lt;br /&gt;
&lt;br /&gt;
grade.php is supplied with the following parameters.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$id = required_param(&#039;id&#039;, PARAM_INT);          // Course module ID&lt;br /&gt;
$itemnumber = optional_param(&#039;itemnumber&#039;, 0, PARAM_INT); // Item number, may be != 0 for activities that allow more than one grade per user&lt;br /&gt;
$userid = optional_param(&#039;userid&#039;, 0, PARAM_INT); // Graded user ID (optional)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Typically you will use has_capability() to determine where to send the user then call redirect().&lt;br /&gt;
&lt;br /&gt;
===Callbacks===&lt;br /&gt;
&lt;br /&gt;
Gradebook callbacks should be available in /mod/$modname/lib.php For example the assignment activity module gradebook callbacks are in /mod/assignment/lib.php&lt;br /&gt;
&lt;br /&gt;
There are three required callbacks.&lt;br /&gt;
&lt;br /&gt;
===={$modname}_supports($feature)====&lt;br /&gt;
&lt;br /&gt;
You activity module needs to define what features it supports. It may well contain a lot of other features but needs to include FEATURE_GRADE_HAS_GRADE if you want to have a grade for your activity. Optionally you can also support FEATURE_GRADE_OUTCOMES if you want to use outcomes.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function assignment_supports($feature) {&lt;br /&gt;
    switch($feature) {&lt;br /&gt;
        case FEATURE_GRADE_HAS_GRADE:         return true;&lt;br /&gt;
        case FEATURE_GRADE_OUTCOMES:          return true;&lt;br /&gt;
&lt;br /&gt;
        default: return null;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===={$modname}_grade_item_update($modinstance, $grades=NULL)====&lt;br /&gt;
&lt;br /&gt;
For example, this callback for the assignment module is assignment_grade_item_update().&lt;br /&gt;
&lt;br /&gt;
This callback should create or update the grade item for a given activity module instance by calling grade_update(). It can update both the activity grade item information and grade&#039;s for users if they are supplied via the $grades parameter.&lt;br /&gt;
&lt;br /&gt;
Typically the $grades parameter also accepts the string &#039;reset&#039; which means that the grades in the gradebook should be reset. This assists with course reset functionality which is described below.&lt;br /&gt;
&lt;br /&gt;
===={$modname}_update_grades($modinstance, $userid=0, $nullifnone=true)====&lt;br /&gt;
&lt;br /&gt;
For example, this callback for the assignment module is assignment_update_grades().&lt;br /&gt;
&lt;br /&gt;
This callback should update the grade(s) for the supplied user. This may be as simple as retrieving the grades for the user from the activity module&#039;s own tables then calling {$modname}_grade_item_update().&lt;br /&gt;
&lt;br /&gt;
Its parameters are:&lt;br /&gt;
# stdClass $modinstance the activity module settings.&lt;br /&gt;
# int $userid A user ID or 0 for all users.&lt;br /&gt;
# bool $nullifnone If a single user is specified, $nullifnone is true and the user has no grade then a grade item with a null rawgrade should be inserted&lt;br /&gt;
&lt;br /&gt;
===Reset Course Support===&lt;br /&gt;
&lt;br /&gt;
Course reset allows a teacher or administrator to remove all user data from a course while retaining settings and activities. Here is a general introduction to [https://docs.moodle.org/en/Reset_course resetting a course]. Here is a guide to [[Implementing_Reset_course_functionality_in_a_module]]&lt;br /&gt;
&lt;br /&gt;
Resetting grades isn&#039;t specifically covered in the reset course implementation guide. The quiz activity module provides a simple example of how it is done. quiz_reset_userdata() contains this code.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (empty($data-&amp;gt;reset_gradebook_grades)) {&lt;br /&gt;
    quiz_reset_gradebook($data-&amp;gt;courseid);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
quiz_reset_gradebook() find all quiz instances then calls quiz_grade_item_update() with the special &#039;reset&#039; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function quiz_reset_gradebook($courseid, $type=&#039;&#039;) {&lt;br /&gt;
    global $CFG, $DB;&lt;br /&gt;
&lt;br /&gt;
    $quizzes = $DB-&amp;gt;get_records_sql(&amp;quot;&lt;br /&gt;
            SELECT q.*, cm.idnumber as cmidnumber, q.course as courseid&lt;br /&gt;
            FROM {modules} m&lt;br /&gt;
            JOIN {course_modules} cm ON m.id = cm.module&lt;br /&gt;
            JOIN {quiz} q ON cm.instance = q.id&lt;br /&gt;
            WHERE m.name = &#039;quiz&#039; AND cm.course = ?&amp;quot;, array($courseid));&lt;br /&gt;
&lt;br /&gt;
    foreach ($quizzes as $quiz) {&lt;br /&gt;
        quiz_grade_item_update($quiz, &#039;reset&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Outcomes Support===&lt;br /&gt;
&lt;br /&gt;
You can choose to support outcomes. There are examples of how to implement outcomes support below. If you want to use outcomes make sure that you include outcomes in your implementation of {$modname}_supports().&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===Inserting or Updating Grades===&lt;br /&gt;
&lt;br /&gt;
===={$modname}_grade_item_update($modinstance, $grades=NULL)====&lt;br /&gt;
&lt;br /&gt;
This is the forum activity module&#039;s implementation of this callback taken from /mod/forum/lib.php. Note that Moodle scales are stored as a positive integer if they are numeric, as a negative integer if they are a custom scale and 0 means the forum is ungraded (this system may be changed by MDL-17258).&lt;br /&gt;
&lt;br /&gt;
Note the special &#039;reset&#039; handling.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function forum_grade_item_update($forum, $grades=NULL) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
    if (!function_exists(&#039;grade_update&#039;)) { //workaround for buggy PHP versions&lt;br /&gt;
        require_once($CFG-&amp;gt;libdir.&#039;/gradelib.php&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $params = array(&#039;itemname&#039;=&amp;gt;$forum-&amp;gt;name, &#039;idnumber&#039;=&amp;gt;$forum-&amp;gt;cmidnumber);&lt;br /&gt;
&lt;br /&gt;
    if (!$forum-&amp;gt;assessed or $forum-&amp;gt;scale == 0) {&lt;br /&gt;
        $params[&#039;gradetype&#039;] = GRADE_TYPE_NONE;&lt;br /&gt;
&lt;br /&gt;
    } else if ($forum-&amp;gt;scale &amp;gt; 0) {&lt;br /&gt;
        $params[&#039;gradetype&#039;] = GRADE_TYPE_VALUE;&lt;br /&gt;
        $params[&#039;grademax&#039;]  = $forum-&amp;gt;scale;&lt;br /&gt;
        $params[&#039;grademin&#039;]  = 0;&lt;br /&gt;
&lt;br /&gt;
    } else if ($forum-&amp;gt;scale &amp;lt; 0) {&lt;br /&gt;
        $params[&#039;gradetype&#039;] = GRADE_TYPE_SCALE;&lt;br /&gt;
        $params[&#039;scaleid&#039;]   = -$forum-&amp;gt;scale;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    if ($grades  === &#039;reset&#039;) {&lt;br /&gt;
        $params[&#039;reset&#039;] = true;&lt;br /&gt;
        $grades = NULL;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return grade_update(&#039;mod/forum&#039;, $forum-&amp;gt;course, &#039;mod&#039;, &#039;forum&#039;, $forum-&amp;gt;id, 0, $grades, $params);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===={$modname}_update_grades($modinstance, $userid=0, $nullifnone=true)====&lt;br /&gt;
&lt;br /&gt;
This is the forum activity module&#039;s implementation of this callback taken from /mod/forum/lib.php.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
function forum_update_grades($forum, $userid=0, $nullifnone=true) {&lt;br /&gt;
    global $CFG, $DB;&lt;br /&gt;
    require_once($CFG-&amp;gt;libdir.&#039;/gradelib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    if (!$forum-&amp;gt;assessed) {&lt;br /&gt;
        forum_grade_item_update($forum);&lt;br /&gt;
&lt;br /&gt;
    } else if ($grades = forum_get_user_grades($forum, $userid)) {&lt;br /&gt;
        forum_grade_item_update($forum, $grades);&lt;br /&gt;
&lt;br /&gt;
    } else if ($userid and $nullifnone) {&lt;br /&gt;
        $grade = new stdClass();&lt;br /&gt;
        $grade-&amp;gt;userid   = $userid;&lt;br /&gt;
        $grade-&amp;gt;rawgrade = NULL;&lt;br /&gt;
        forum_grade_item_update($forum, $grade);&lt;br /&gt;
&lt;br /&gt;
    } else {&lt;br /&gt;
        forum_grade_item_update($forum);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It checks if the forum is assessed (is gradeable). If it is not the forum object is passed to forum_grade_item_update() so settings like the grading scale being used can be saved.&lt;br /&gt;
&lt;br /&gt;
If the forum is assessed it attempts to load user grades. forum_get_user_grades() does this by accessing the [[Rating_API]] however your activity module may instead access its own tables. You should handle a user ID of 0 being supplied.&lt;br /&gt;
&lt;br /&gt;
If the user has no grade (or a user ID of 0 was supplied) and if $nullifnone is true then a grade with rawgrade == NULL is inserted.&lt;br /&gt;
&lt;br /&gt;
===Retrieving Grades===&lt;br /&gt;
&lt;br /&gt;
This is an example of how to retrieve user grades.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//$users == array of users&lt;br /&gt;
$grading_info = grade_get_grades($courseid, &#039;mod&#039;, $modname, $modinstance-&amp;gt;id, array_keys($users));&lt;br /&gt;
&lt;br /&gt;
$grade_item_grademax = $grading_info-&amp;gt;items[0]-&amp;gt;grademax;&lt;br /&gt;
foreach ($users as $user) {&lt;br /&gt;
    $user_final_grade = $grading_info-&amp;gt;items[0]-&amp;gt;grades[$user-&amp;gt;id];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Inserting or Updating Outcome Grade Items===&lt;br /&gt;
&lt;br /&gt;
Working with outcome grade items is slightly more complex than &amp;quot;regular&amp;quot; grade items.&lt;br /&gt;
&lt;br /&gt;
Make sure to observe the value of $CFG-&amp;gt;enableoutcomes as outcomes may be enabled or disabled at site level. &lt;br /&gt;
&lt;br /&gt;
====Inserting Outcome Grade Items====&lt;br /&gt;
&lt;br /&gt;
The process to insert an outcome grade item is a little long but its not complicated. First, create a new grade_object. An ID of 0 means new.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$grade_item = new grade_item(array(&#039;id&#039;=&amp;gt;0, &#039;courseid&#039;=&amp;gt;$courseid));&lt;br /&gt;
grade_item::set_properties($grade_item, $data);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
$data is an instance of stdClass similar to this.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
stdClass Object&lt;br /&gt;
(&lt;br /&gt;
    [itemname] =&amp;gt; &#039;Reading comprehension&#039; // the outcome name&lt;br /&gt;
    [iteminfo] =&amp;gt; &lt;br /&gt;
    [idnumber] =&amp;gt;    //blank for now&lt;br /&gt;
    [outcomeid] =&amp;gt; 1 // the outcome ID&lt;br /&gt;
    [cmid] =&amp;gt; 0&lt;br /&gt;
    [id] =&amp;gt; 0        // 0 means new&lt;br /&gt;
    [courseid] =&amp;gt; 2  // the course ID&lt;br /&gt;
    [aggregationcoef] =&amp;gt; 0&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now give the outcome grade item a unique itemnumber. The activity&#039;s original grade item will have a itemnumber of 0. If you have multiple outcome grade items per activity you may need to query the database to check itemnumber is unique.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$grade_item-&amp;gt;itemnumber = $uniqueitemnumber;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Set the outcome grade item to use the outcome&#039;s scale then insert the grade item into the database.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$outcome = grade_outcome::fetch(array(&#039;id&#039;=&amp;gt;$outcomeid));&lt;br /&gt;
$grade_item-&amp;gt;gradetype = GRADE_TYPE_SCALE;&lt;br /&gt;
$grade_item-&amp;gt;scaleid = $outcome-&amp;gt;scaleid;&lt;br /&gt;
&lt;br /&gt;
$grade_item-&amp;gt;insert(); //or maybe $grade_item-&amp;gt;update();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Finally load the activity&#039;s original grade item, put the outcome grade item in the same category and check that the sort order is correct.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($item = grade_item::fetch(array(&#039;itemtype&#039;=&amp;gt;&#039;mod&#039;, &#039;itemmodule&#039;=&amp;gt;$grade_item-&amp;gt;itemmodule,&lt;br /&gt;
        &#039;iteminstance&#039;=&amp;gt;$grade_item-&amp;gt;iteminstance, &#039;itemnumber&#039;=&amp;gt;0, &#039;courseid&#039;=&amp;gt;$COURSE-&amp;gt;id))) {&lt;br /&gt;
    $grade_item-&amp;gt;set_parent($item-&amp;gt;categoryid);&lt;br /&gt;
    $grade_item-&amp;gt;move_after_sortorder($item-&amp;gt;sortorder);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Inserting Student Grades For Outcome Grade Items====&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;itemnumber&amp;quot; is the key to inserting outcome grades. All grade item&#039;s for an activity module will have the same itemtype, usually &#039;mod&#039;, the same itemmodule, something like &#039;assignment&#039; or &#039;forum&#039;, and the same iteminstance, the integer ID of the module instance. The itemnumber is 0 for the activity&#039;s primary grade item but will be a number greater than 1 for outcome grade items attached to the activity.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if (empty($CFG-&amp;gt;enableoutcomes)) {&lt;br /&gt;
    return;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
require_once($CFG-&amp;gt;libdir.&#039;/gradelib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$data = array();&lt;br /&gt;
$grading_info = grade_get_grades($courseid, &#039;mod&#039;, $modtype, $modinstance-&amp;gt;id, $userid);&lt;br /&gt;
&lt;br /&gt;
if (!empty($grading_info-&amp;gt;outcomes)) {&lt;br /&gt;
    foreach($grading_info-&amp;gt;outcomes as $n=&amp;gt;$old) {&lt;br /&gt;
         $data[$n] = 2; //new student grade for this outcome == 2, $n == &amp;quot;itemnumber&amp;quot;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
if (count($data) &amp;gt; 0) {&lt;br /&gt;
    grade_update_outcomes(&#039;mod/&#039;.$modtype, $courseid, &#039;mod&#039;, $modtype, $modinstance-&amp;gt;id, $userid, $data);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=63911</id>
		<title>lib/formslib.php Form Definition</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=63911"/>
		<updated>2023-06-05T13:13:42Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: Move and outdent RTL support; outdent float&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Formslib}}&lt;br /&gt;
== &#039;&#039;definition()&#039;&#039; ==&lt;br /&gt;
The definition of the elements to be included in the form, their &#039;types&#039; (PARAM_*), helpbuttons included, etc. is all included in a function you must define in your class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;definition()&#039;&#039; is used to define the elements in the form and &#039;&#039;&#039;this definition will be used for validating data submitted as well as for printing the form.&#039;&#039;&#039; For select and checkbox type elements only data that could have been selected will be allowed. And only data that corresponds to a form element in the definition will be accepted as submitted data.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;definition()&#039;&#039; should include all elements that are going to be used on form, some elements may be removed or tweaked later in &#039;&#039;definition_after_data()&#039;&#039;. Please do not create conditional elements in &#039;&#039;definition()&#039;&#039;, the definition() should not directly depend on the submitted data.&lt;br /&gt;
&lt;br /&gt;
Note that the definition function is called when the form class is instantiated. There is no option to (say) manipulate data in the class (that may affect the rendering of the form) between instantiating the form and calling any other methods. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;libdir/formslib.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
class simplehtml_form extends moodleform {&lt;br /&gt;
&lt;br /&gt;
    function definition() {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
       &lt;br /&gt;
        $mform = $this-&amp;gt;_form; // Don&#039;t forget the underscore! &lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement()... // Add elements to your form&lt;br /&gt;
            ...&lt;br /&gt;
    }                           // Close the function&lt;br /&gt;
}                               // Close the class&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===Passing parameters to the Form===&lt;br /&gt;
The constructor for &#039;&#039;moodleform&#039;&#039; allows a number of parameters including one (&#039;&#039;$customdata&#039;&#039;) to permit an array of arbitrary data to be passed to your form. &lt;br /&gt;
&lt;br /&gt;
For example, you can pass the data &amp;quot;$email&amp;quot; and &amp;quot;$username&amp;quot; to the Form&#039;s class for use inside (say) the definition.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform_simple = new simplehtml_form( null, array(&#039;email&#039;=&amp;gt;$email, &#039;username&#039;=&amp;gt;$username ) );&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
(the first parameter is $action, &#039;&#039;null&#039;&#039; will cause the form action to be determined automatically)&lt;br /&gt;
&lt;br /&gt;
Secondly, inside the form definition you can use those parameters to set the default values to some of the form&#039;s fields&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;), &#039;maxlength=&amp;quot;100&amp;quot; size=&amp;quot;25&amp;quot; &#039;);&lt;br /&gt;
 $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);&lt;br /&gt;
 $mform-&amp;gt;addRule(&#039;email&#039;, get_string(&#039;missingemail&#039;), &#039;required&#039;, null, &#039;server&#039;);&lt;br /&gt;
 // Set default value by using a passed parameter&lt;br /&gt;
 $mform-&amp;gt;setDefault(&#039;email&#039;,$this-&amp;gt;_customdata[&#039;email&#039;]);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Use Fieldsets to group Form Elements==&lt;br /&gt;
You use code like this to open a fieldset with a &#039;&#039;legend&#039;&#039;. &amp;lt;br /&amp;gt;&lt;br /&gt;
(&#039;&#039;&#039;Note&#039;&#039;&#039;: Some themes turn off legends on admin setting pages by using CSS: &amp;lt;nowiki&amp;gt;#adminsettings legend {display:none;}&amp;lt;/nowiki&amp;gt;.)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;header&#039;, &#039;nameforyourheaderelement&#039;, get_string(&#039;titleforlegened&#039;, &#039;modulename&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can&#039;t yet nest these visible fieldsets unfortunately. But in fact groups of elements are wrapped in invisible fieldsets.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
Since Moodle 2.5 fieldsets without any required fields are collapsed by default. To display these fieldsets on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To close a fieldset on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You close a fieldset with moodle_form&#039;s closeHeaderBefore method. You tell closeHeaderBefore the element before you wish to end the fieldset. A fieldset is automatically closed if you open a new one. You need to use this code only if you want to close a fieldset and the subsequent form elements are not to be enclosed by a visible fieldset (they are still enclosed with an invisibe one with no legend) :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;closeHeaderBefore(&#039;buttonar&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==addElement==&lt;br /&gt;
Use the addElement method to add an element to a form. The first few arguments are always the same. The first param is the type of the element to add. The second is the elementname to use which is normally the html name of the element in the form. The third is often the text for the label for the element.&lt;br /&gt;
&lt;br /&gt;
Some examples are below :&lt;br /&gt;
=== button ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;button&#039;, &#039;intro&#039;, get_string(&amp;quot;buttonlabel&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A button element. If you want a submit or cancel button see &#039;submit&#039; element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== autocomplete ===&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
Available since Moodle 3.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$searchareas = \core_search\manager::get_search_areas_list(true);                                                           &lt;br /&gt;
$areanames = array();                                                                                                       &lt;br /&gt;
foreach ($searchareas as $areaid =&amp;gt; $searcharea) {                                                                          &lt;br /&gt;
    $areanames[$areaid] = $searcharea-&amp;gt;get_visible_name();                                                                  &lt;br /&gt;
}                                                                                                                           &lt;br /&gt;
$options = array(                                                                                                           &lt;br /&gt;
    &#039;multiple&#039; =&amp;gt; true,                                                  &lt;br /&gt;
    &#039;noselectionstring&#039; =&amp;gt; get_string(&#039;allareas&#039;, &#039;search&#039;),                                                                &lt;br /&gt;
);         &lt;br /&gt;
$mform-&amp;gt;addElement(&#039;autocomplete&#039;, &#039;areaids&#039;, get_string(&#039;searcharea&#039;, &#039;search&#039;), $areanames, $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The autocomplete element is an advanced form element that supports server-side searching - or simple filtering of a predefined list of options. Some benefits of using this form element are that it handles very large datasets extremely well - it has great accessibility built in - and it gives a good user experience. If you have so much data you need to build pagination into a page - you could probably come up with a better design using this. The simplest way to use it is compatible with the standard &#039;select&#039; form element. You give it a list of options and some parameters to configure how it behaves. The valid parameters for this simple mode of operation are:&lt;br /&gt;
* multiple (boolean - default false) - Allow more than one selected item. The data coming from the form will be an array in this case.&lt;br /&gt;
[[image:autocomplete_multiple2.png|center|thumb|alt=autocomplete with multiple option|autocomplete with multiple option.]]&lt;br /&gt;
* noselectionstring (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to display when nothing is selected.&lt;br /&gt;
* showsuggestions (boolean - default true) - Do not show the list of suggestions when the user starts typing.&lt;br /&gt;
* placeholder (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to show in the search box when it is empty.&lt;br /&gt;
* casesensitive (boolean - default false) - Is the search case sensitive ?&lt;br /&gt;
* tags (boolean - default false) - This changes the behaviour so that the user can create new valid entries in the list by typing them and pressing enter.&lt;br /&gt;
* ajax (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - This string is the name of an AMD module that can fetch and format results.&lt;br /&gt;
* valuehtmlcallback - For use with the AJAX option, so that it can format the initial value of the form field (available since Moodle 3.5)&lt;br /&gt;
More explanation on the &#039;ajax&#039; option. This should be the name of an AMD module that implements 2 functions:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Source of data for Ajax element.&lt;br /&gt;
 *&lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.&lt;br /&gt;
 * @param {String} query The query string.                        &lt;br /&gt;
 * @param {Function} callback A callback function receiving an array of results.&lt;br /&gt;
 * @param {Function} failure A callback function to be called in case of failure, receiving the error message.&lt;br /&gt;
 * @return {Void}                                                                                                           &lt;br /&gt;
*/                                                                                                                         &lt;br /&gt;
transport: function(selector, query, callback, failure) ...&lt;br /&gt;
&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Process the results for auto complete elements.                                                                          &lt;br /&gt;
 *                                                                                                                          &lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.                                                      &lt;br /&gt;
 * @param {Array} results An array or results.                                                                              &lt;br /&gt;
 * @return {Array} New array of results.                                                                                    &lt;br /&gt;
 */                                                                                                                         &lt;br /&gt;
processResults: function(selector, results)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A good example is here: [https://github.com/moodle/moodle/blob/master/admin/tool/lp/amd/src/frameworks_datasource.js admin/tool/lp/amd/src/frameworks_datasource.js]&lt;br /&gt;
&lt;br /&gt;
The &#039;valuehtmlcallback&#039; function is needed when an AJAX-supporting form field has an initial value that needs special rendering, similar to how the AJAX code would render it when the user changes it dynamically. For example, if the field contains user ids and its initial value is &#039;1,2&#039; then you want it to use the rendered HTML display for each value (probably a user&#039;s name and picture), not just display those numbers. Here is an example, from /search/classes/output/form/search.php:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&#039;valuehtmlcallback&#039; =&amp;gt; function($value) {&lt;br /&gt;
    global $DB, $OUTPUT;&lt;br /&gt;
    $user = $DB-&amp;gt;get_record(&#039;user&#039;, [&#039;id&#039; =&amp;gt; (int)$value], &#039;*&#039;, IGNORE_MISSING);&lt;br /&gt;
    if (!$user || !user_can_view_profile($user)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
    $details = user_get_user_details($user);&lt;br /&gt;
    return $OUTPUT-&amp;gt;render_from_template(&lt;br /&gt;
        &#039;core_search/form-user-selector-suggestion&#039;, $details);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The Mustache template used here is the same as the one used by the AJAX code when the field is changed dynamically.&lt;br /&gt;
&lt;br /&gt;
When using the ajax option in an mform with validation etc - it is recommended to sub-class the php class &amp;quot;MoodleQuickForm_autocomplete&amp;quot; so that you can provide a list of name and&lt;br /&gt;
values to populate the form element if the form is re-displayed due to a validation error. An example is [https://github.com/moodle/moodle/blob/MOODLE_31_STABLE/admin/tool/lp/classes/form/framework_autocomplete.php admin/tool/lp/classes/form/framework_autocomplete.php].&lt;br /&gt;
&lt;br /&gt;
We have provided several useful subclasses of this form element already that are simple to use (course and tags).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt; &lt;br /&gt;
    // Course example.&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;multiple&#039; - boolean multi select                                                                      &lt;br /&gt;
    //                       &#039;exclude&#039; - array or int, list of course ids to never show                                             &lt;br /&gt;
    //                       &#039;requiredcapabilities&#039; - array of capabilities. Uses ANY to combine them.                              &lt;br /&gt;
    //                       &#039;limittoenrolled&#039; - boolean Limits to enrolled courses.                                                &lt;br /&gt;
    //                       &#039;includefrontpage&#039; - boolean Enables the frontpage to be selected.  &lt;br /&gt;
    $options = array(&#039;multiple&#039; =&amp;gt; true, &#039;includefrontpage&#039; =&amp;gt; true);                                                           &lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course&#039;, &#039;mappedcourses&#039;, get_string(&#039;courses&#039;), $options); &lt;br /&gt;
&lt;br /&gt;
    // Tags&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;showstandard&#039; - boolean One of the core_tag_tag constants to say which tags to display&lt;br /&gt;
    //                       &#039;component&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    //                       &#039;itemtype&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;tags&#039;, &#039;interests&#039;, get_string(&#039;interestslist&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;user&#039;, &#039;component&#039; =&amp;gt; &#039;core&#039;));     &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== checkbox ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a simple checkbox. The third parameter for this element is the label to display on the left side of the form. You can also supply a string as a fourth parameter to specify a label that will appear on the right of the element. Checkboxes and radio buttons can be grouped and have individual labels on their right.&lt;br /&gt;
&lt;br /&gt;
You can have a 5th parameter $attributes, as on other elements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BEWARE:&#039;&#039;&#039; Unchecked checkboxes return nothing at all (as if they didn&#039;t exist). This can surprise the unwary. You may wish to use advcheckbox instead, which does return a value when not checked. &#039;Advcheckbox&#039; eliminates this problem. &lt;br /&gt;
==== advcheckbox ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;), &#039;Label displayed after checkbox&#039;, array(&#039;group&#039; =&amp;gt; 1), array(0, 1));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Similar to the checkbox above, but with some important improvements:&lt;br /&gt;
# The (optional) 5th parameter is a normal $attributes array, normally used to set HTML attributes for the &amp;lt;input&amp;gt; element. However, a special value of &#039;group&#039; can be given, which will add a class name to the element, and enable its grouping for a [[lib/formslib.php_add_checkbox_controller|checkbox controller]]&lt;br /&gt;
#The (optional) 6th parameter is an array of values that will be associated with the checked/unchecked state of the checkbox. With a normal checkbox you cannot choose that value, and in fact an unchecked checkbox will not even be sent with the form data.&lt;br /&gt;
#It returns a 0 value when unchecked. Compare with the ordinary checkbox which does not return anything at all.&lt;br /&gt;
=== choosecoursefile ===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;choosecoursefile&#039;, &#039;mediafile&#039;, get_string(&#039;mediafile&#039;, &#039;lesson&#039;), array(&#039;courseid&#039;=&amp;gt;$COURSE-&amp;gt;id));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Choose a file from the course files area. The fourth option is a list of options for the element. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: This has been superceded by [[#filepicker|filepicker]] in Moodle 2.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&#039;courseid&#039; =&amp;gt;null,  //if it is null (default then use global $COURSE&lt;br /&gt;
      &#039;height&#039;   =&amp;gt;500,   // height of the popup window&lt;br /&gt;
      &#039;width&#039;    =&amp;gt;750,   // width of the popup window&lt;br /&gt;
      &#039;options&#039;  =&amp;gt;&#039;none&#039;); //options string for the pop up window &lt;br /&gt;
                          //eg. &#039;menubar=0,location=0,scrollbars,resizable&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;maxlength&#039; =&amp;gt; 255, &#039;size&#039; =&amp;gt; 48)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the maxlength / size of the text box (note size will default to 48 if not specified)&lt;br /&gt;
&lt;br /&gt;
Finally, as this element is a group containing two elements (button + value), you can add validation rules by using the &#039;&#039;&#039;addGroupRule()&#039;&#039;&#039; method in this (complex) way:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;elementname&#039;, array(&#039;value&#039; =&amp;gt; array(array(list, of, rule, params, but, fieldname))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Where: &#039;&#039;&#039;&amp;quot;elementname&amp;quot;&#039;&#039;&#039; is the name of the choosecoursefile group element, &#039;&#039;&#039;&amp;quot;value&amp;quot;&#039;&#039;&#039; is the name of the text field within the group and the &#039;&#039;&#039;&amp;quot;list, of, addrule, params, but, fieldname&amp;quot;&#039;&#039;&#039; is exactly that, the list of fields in the normal addRule() function but ommiting the first one, the fieldname.&lt;br /&gt;
&lt;br /&gt;
For example, the [http://cvs.moodle.org/moodle/mod/resource/type/file/resource.class.php?view=markup file/url resource type], uses one &amp;quot;choosecoursefile&amp;quot; element, and it controls the maximum length of the field (255) with this use of addGroupRule():&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;reference&#039;, array(&#039;value&#039; =&amp;gt; array(array(get_string(&#039;maximumchars&#039;, &#039;&#039;, 255), &#039;maxlength&#039;, 255, &#039;client&#039;))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== date_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_selector&#039;, &#039;assesstimefinish&#039;, get_string(&#039;to&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a date selector. You can select a Day, Month and Year using a group of select boxes. The fourth param here is an array of options. The defaults for the options are :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;optional&#039;  =&amp;gt; false&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. You can supply a fifth param of attributes here as well.&lt;br /&gt;
=== date_time_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_time_selector&#039;, &#039;assesstimestart&#039;, get_string(&#039;from&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a group of select boxes to select a date (Day Month and Year) and time (Hour and Minute). When submitted, submitted data is processed and a timestamp is passed to $form-&amp;gt;get_data(); the fourth param here is an array of options. The defaults for the options are:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;step&#039;      =&amp;gt; 5,&lt;br /&gt;
    &#039;optional&#039; =&amp;gt; false,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. Setting &#039;optional&#039; to true adds an &#039;enable&#039; checkbox to the selector. You can supply a fifth param of attributes here as well.&lt;br /&gt;
===duration===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;duration&#039;, &#039;timelimit&#039;, get_string(&#039;timelimit&#039;, &#039;quiz&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This field type lets the user input an interval of time. It comprises a text field, where you can type a number, and a dropdown for selecting a unit (days, hours, minutes or seconds). When submitted the value is converted to a number of seconds.&lt;br /&gt;
&lt;br /&gt;
You can add a fourth parameter to give options. At the moment the only option supported is here is an array of options. The defaults for the options is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;optional&#039; =&amp;gt; true)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;size&#039; =&amp;gt; 5)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the size of the text box.&lt;br /&gt;
=== editor ===&lt;br /&gt;
This replaces the old htmleditor field type. It allows the user to enter rich text content in a variety of formats.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;fieldname&#039;, get_string(&#039;labeltext&#039;, &#039;langfile&#039;));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;fieldname&#039;, PARAM_RAW);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
NOTE: It won&#039;t work properly without the setType() as shown.&lt;br /&gt;
&lt;br /&gt;
If you would like to let the user use the filepicker to upload images etc. that are used in the content, then see [[Using_the_File_API_in_Moodle_forms]].&lt;br /&gt;
&lt;br /&gt;
You can supply a fifth param to htmleditor of an array of options that are mostly related to file handling:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;subdirs&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxbytes&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxfiles&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;changeformat&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;context&#039;=&amp;gt;null,&lt;br /&gt;
    &#039;noclean&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;trusttext&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;enable_filemanagement&#039; =&amp;gt; true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The option &#039;enable_filemanagement&#039; will display the file management button on true and remove it on false.&lt;br /&gt;
&lt;br /&gt;
To save the data if you don&#039;t care about files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$text     = $formdata-&amp;gt;fieldname[&#039;text&#039;];&lt;br /&gt;
$format   = $formdata-&amp;gt;fieldname[&#039;format&#039;];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: Because the text editor might be &amp;quot;Atto&amp;quot; (depending on user preferences) and Atto has an &amp;quot;autosave&amp;quot; feature - it requires that the combination of $PAGE-&amp;gt;url and this elementid are unique. If not, the autosaved text for a different form may be restored into this form.&lt;br /&gt;
=== file ===&lt;br /&gt;
File upload input box with browse button. In the form definition type&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
after form submission and validation use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If there is no requirement to save the file, you can read the file contents directly into a string as follows...&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    $mform-&amp;gt;get_file_content(&#039;attachment&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you need advanced settings such as required file, different max upload size or name of uploaded file&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0, true, true, false));&lt;br /&gt;
            $mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
            $mform-&amp;gt;addRule(&#039;attachment&#039;, null, &#039;required&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
    $newfilename = $mform-&amp;gt;get_new_filename();&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When porting old code it is also possible to use the upload manager directly for processing of uploaded files.&lt;br /&gt;
&lt;br /&gt;
Please note that if using set_upload_manager() it must be before addElement(&#039;file&#039;,..).&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
File uploading was rewritten in 2.0. Please see inline docs for now. This page will be updated when the new API stabilises.&lt;br /&gt;
===filepicker===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
General replacement of &#039;&#039;file&#039;&#039; element.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null, array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See also [[Using the File API in Moodle forms]]&lt;br /&gt;
=== hidden ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;hidden&#039;, &#039;reply&#039;, &#039;yes&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A hidden element. Set the element name (in this case &#039;&#039;&#039;reply&#039;&#039;&#039;) to the stated value (in this case &#039;&#039;&#039;yes&#039;&#039;&#039;).&lt;br /&gt;
=== html ===&lt;br /&gt;
You can add arbitrary HTML to your Moodle form:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;html&#039;, &#039;&amp;lt;div class=&amp;quot;qheader&amp;quot;&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See [http://moodle.org/mod/forum/discuss.php?d=126935 &amp;quot;Question: Can I put a moodleform inside a table td?&amp;quot;] for a concrete example.&lt;br /&gt;
=== htmleditor &amp;amp; format ===&lt;br /&gt;
These elements are now deprecated. Please use the [[#editor|editor]] field type instead.&lt;br /&gt;
===modgrade===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modgrade&#039;, &#039;scale&#039;, get_string(&#039;grade&#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade for any activity module. The fourth argument is whether to include an option for no grade which has a value 0. This select box does include scales. The default is true, include no grade option.&lt;br /&gt;
&lt;br /&gt;
A helpbutton is automatically added.&lt;br /&gt;
===modvisible===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modvisible&#039;, &#039;visible&#039;, get_string(&#039;visible&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade visibility in an activity mod update form.&lt;br /&gt;
===password===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;password&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element. Fourth param is an array or string of attributes.&lt;br /&gt;
===passwordunmask===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;passwordunmask&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element with option to show the password in plaintext. Fourth param is an array or string of attributes.&lt;br /&gt;
=== radio ===&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$radioarray=array();&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;yes&#039;), 1, $attributes);&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;no&#039;), 0, $attributes);&lt;br /&gt;
$mform-&amp;gt;addGroup($radioarray, &#039;radioar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Second param names the radio button and should be the same for each button in the group in order to toggle correctly. Third param would be the label for the form element but is generally ignored as this element will always be in a group which has it&#039;s own label. Fourth param is a string, a label to be displayed on the right of the element. The fifth is the value for this radio button. $attributes can be a string or an array of attributes.&lt;br /&gt;
&lt;br /&gt;
It is possible to add help to individual radio buttons but this requires a custom template to be defined for the group elements. See MDL-15571.&lt;br /&gt;
&lt;br /&gt;
Since 2.3 it cannot be statically called anymore, so we need to call createElement from $mform reference.&lt;br /&gt;
==== setDefault ====&lt;br /&gt;
To set the default for a radio button group as above use the following :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;yesno&#039;, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This would make the default &#039;no&#039;.&lt;br /&gt;
===select===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;type&#039;, get_string(&#039;forumtype&#039;, &#039;forum&#039;), $FORUM_TYPES, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The fourth param for this element is an array of options for the select box. The keys are the values for the option and the value of the array is the text for the option. The fifth param $attributes is optional, see text element for description of attributes param.&lt;br /&gt;
&lt;br /&gt;
It is also possible to create a select with certain options disabled, using [http://stackoverflow.com/questions/2138089/how-can-i-use-quickform-to-add-disabled-select-options/2150275#2150275 this technique].&lt;br /&gt;
&lt;br /&gt;
You can set an &#039;onchange&#039; attribute when adding or creating the select element: &lt;br /&gt;
&lt;br /&gt;
$form-&amp;gt;addElement(&#039;select&#039;, &#039;iselTest&#039;, &#039;Test Select:&#039;, $arrayOfOptions, array(&#039;onchange&#039; =&amp;gt; &#039;javascript:myFunctionToDoSomething();&#039;));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====multi-select====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), array(&#039;red&#039;, &#039;blue&#039;, &#039;green&#039;), $attributes);&lt;br /&gt;
$select-&amp;gt;setMultiple(true);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====setSelected=====&lt;br /&gt;
To set the default selected item in a select element, you can use the &#039;setSelected&#039; method. The &#039;setSelected&#039; can either get a value or an array of values.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array(&lt;br /&gt;
    &#039;ff0000&#039; =&amp;gt; &#039;Red&#039;,&lt;br /&gt;
    &#039;00ff00&#039; =&amp;gt; &#039;Green&#039;,&lt;br /&gt;
    &#039;0000ff&#039; =&amp;gt; &#039;Blue&#039;&lt;br /&gt;
);&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), $options);&lt;br /&gt;
// This will select the colour blue.&lt;br /&gt;
$select-&amp;gt;setSelected(&#039;0000ff&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or for multiple-selection:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$skillsarray = array(&lt;br /&gt;
    &#039;val1&#039; =&amp;gt; &#039;Skill A&#039;,&lt;br /&gt;
    &#039;val2&#039; =&amp;gt; &#039;Skill B&#039;,&lt;br /&gt;
    &#039;val3&#039; =&amp;gt; &#039;Skill C&#039;&lt;br /&gt;
);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;md_skills&#039;, get_string(&#039;skills&#039;, &#039;metadata&#039;), $skillsarray);&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setMultiple(true);&lt;br /&gt;
// This will select the skills A and B.&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setSelected(array(&#039;val1&#039;, &#039;val2&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
However you probably don&#039;t want to do this. Instead you probably want to use setDefault, or set it using the form&#039;s setData method.&lt;br /&gt;
===selectyesno===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;maxbytes&#039;, get_string(&#039;maxattachmentsize&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you want a yes / no select box this one automatically translates itself and has value 1 for yes and 0 for no.&lt;br /&gt;
===selectwithlink===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array();&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectwithlink&#039;, &#039;scaleid&#039;, get_string(&#039;scale&#039;), $options, null, &lt;br /&gt;
    array(&#039;link&#039; =&amp;gt; $CFG-&amp;gt;wwwroot.&#039;/grade/edit/scale/edit.php?courseid=&#039;.$COURSE-&amp;gt;id, &#039;label&#039; =&amp;gt; get_string(&#039;scalescustomcreate&#039;)));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
select type element with options containing link&lt;br /&gt;
===static===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;description&#039;, &#039;exercise&#039;),&lt;br /&gt;
    get_string(&#039;descriptionofexercise&#039;, &#039;exercise&#039;, $COURSE-&amp;gt;students));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a static element. It should be used with care if it is used to display a static piece of text with a label. The third param is the label and the fourth is the static text itself.&lt;br /&gt;
===submit, reset and cancel===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//normally you use add_action_buttons instead of this code&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;reset&#039;, &#039;resetbutton&#039;, get_string(&#039;revert&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;cancel&#039;);&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, &#039; &#039;, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A &#039;Submit&#039; type element is a submit type form element which will submit the form. A &#039;Reset&#039; will not submit the form but will reset any changes the user has made to form contents. A &#039;Cancel&#039; element cancels form submission. You need to have a branch in your code before you check for get_data() to check if submission has been cancelled with is_cancelled(); See the example on the usage page.&lt;br /&gt;
&lt;br /&gt;
You should name your submit and reset buttons &#039;submitbutton&#039; and &#039;resetbutton&#039; or something similar (not &#039;submit&#039; and &#039;reset&#039;). This avoids problems in JavaScript of collisions between form element names and names of JavaScript methods of the form object.&lt;br /&gt;
====add_action_buttons($cancel = true, $submitlabel=null);====&lt;br /&gt;
You will normally use this helper function which is a method of moodleform to add all the &#039;action&#039; buttons to the end of your form. A boolean parameter allow you to specify whether to include a cancel button and specify the label for your submit button (pass the result of get_string). Default for the submit button label is get_string(&#039;savechanges&#039;). Note the &#039;&#039;&#039;$this&#039;&#039;&#039; not &#039;&#039;&#039;$mform&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===text===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;name&#039;, get_string(&#039;forumname&#039;, &#039;forum&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For a simple text input element. (For text labels, use the &#039;static&#039; element.) Your fourth parameter here can be a string or array of attributes for the text element. The following are equivalent :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$attributes=&#039;size=&amp;quot;20&amp;quot;&#039;;&lt;br /&gt;
$attributes=array(&#039;size&#039;=&amp;gt;&#039;20&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Generally you are encouraged to use CSS instead of using attributes for styling.&lt;br /&gt;
&lt;br /&gt;
===float===&lt;br /&gt;
{{Moodle 3.7}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;float&#039;, &#039;defaultmark&#039;, get_string(&#039;defaultmark&#039;, &#039;question&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use the float element if you want a text box to get a floating point number. This element automatically supports localised decimal separators. You don&#039;t need to use setType with the float element.&lt;br /&gt;
&lt;br /&gt;
===textarea===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;textarea&#039;, &#039;introduction&#039;, get_string(&amp;quot;introtext&amp;quot;, &amp;quot;survey&amp;quot;), &#039;wrap=&amp;quot;virtual&amp;quot; rows=&amp;quot;20&amp;quot; cols=&amp;quot;50&amp;quot;&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A textarea element. If you want an htmleditor use htmleditor element. Fourth element here is a string or array of attributes.&lt;br /&gt;
===recaptcha===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;recaptcha&#039;, &#039;recaptcha_field_name&#039;, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use this recaptcha element to reduce the spam risk in your forms. Third element here is a string or array of attributes. Take care to get an API key from http://recaptcha.net/api/getkey before using this element.&lt;br /&gt;
&lt;br /&gt;
To check whether recaptcha is enabled at site level use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (!empty($CFG-&amp;gt;recaptchapublickey) &amp;amp;&amp;amp; !empty($CFG-&amp;gt;recaptchaprivatekey)) {&lt;br /&gt;
    //recaptcha is enabled&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===tags===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;field_name&#039;, $lable, $options, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Used for editing a list of tags, for example on a blog post.&lt;br /&gt;
&lt;br /&gt;
There is only one option available, &#039;display&#039;, which should be set to one of the contstants MoodleQuickForm_tags::ONLYOFFICIAL, NOOFFICIAL or DEFAULTUI. This controls whether the official tags are listed for easy selection, or a text area where arbitrary tags may be typed, or both. The default is both.&lt;br /&gt;
&lt;br /&gt;
The value should be set/returned as an array of tags.&lt;br /&gt;
===grading===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;grading&#039;, &#039;advancedgrading&#039;, get_string(&#039;grade&#039;).&#039;:&#039;, array(&#039;gradinginstance&#039; =&amp;gt; $gradinginstance));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Custom element for advanced grading plugins.&lt;br /&gt;
&lt;br /&gt;
When adding the &#039;grading&#039; element to the form, developer must pass an object of class gradingform_instance as $attributes[&#039;gradinginstance&#039;]. Otherwise an exception will be thrown.&lt;br /&gt;
===questioncategory===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;questioncategory&#039;, &#039;category&#039;, get_string(&#039;category&#039;, &#039;question&#039;),&lt;br /&gt;
    array(&#039;contexts&#039;=&amp;gt;$contexts, &#039;top&#039;=&amp;gt;true, &#039;currentcat&#039;=&amp;gt;$currentcat, &#039;nochildrenof&#039;=&amp;gt;$currentcat));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates a drop down element to select a question category.&lt;br /&gt;
&lt;br /&gt;
Options are:&lt;br /&gt;
&#039;&#039;&#039;contexts&#039;&#039;&#039; - (required) context in which question appears&lt;br /&gt;
&#039;&#039;&#039;currentcat&#039;&#039;&#039; - (optional) course category&lt;br /&gt;
&#039;&#039;&#039;top&#039;&#039;&#039; - (optional) if true will put top categories on top&lt;br /&gt;
&#039;&#039;&#039;nochildrenof&#039;&#039;&#039; - (optional) Format categories into an indented list reflecting the tree structure&lt;br /&gt;
=== filetypes ===&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
Available since Moodle 3.4&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;allowedfiletypes&#039;, get_string(&#039;allowedfiletypes&#039;, &#039;tool_myplugin&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates an input element allowing the user to specify file types for the given purpose. The typical scenario is a setting that allows the teacher define a list of allowed file types submitted by students.&lt;br /&gt;
&lt;br /&gt;
The element allows the user to either type the list of filetypes manually, or select the types from the list. Also supported is selecting the whole group of file types - such as &amp;quot;image&amp;quot;. The element integrates with the [[Core filetypes]] system so all default types and groups are presented, as well as those [[:en:Working with files#Site administration settings|defined locally by the admin]].&lt;br /&gt;
&lt;br /&gt;
As the list can be types in manually, the form processing code should always normalize it first via the provided utility methods:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$allowedfiletypes = $filetypesutil-&amp;gt;normalize_file_types($formdata-&amp;gt;allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This always returns an array of recognized valid values. The original list can be separated by whitespace, end of lines, commas, colons and semicolons. During the normalization, values are converted to lowercase, empty valies and duplicates are removed. Glob evaluation is not supported.&lt;br /&gt;
&lt;br /&gt;
The normalization should also happen if the previously defined list had been saved to the database and re-read for actual usage. The normalization output value can be directly used as the accepted_types option for the filepicker.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$options[&#039;accepted_types&#039;] = $filetypesutil-&amp;gt;normalize_file_types($allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
By default, user input is validated against the list of known file types and groups. This validation can be disabled via options.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Supported options&#039;&#039;&#039;&lt;br /&gt;
; onlytypes : Allow selection from these file types only; for example [&#039;onlytypes&#039; =&amp;gt; [&#039;web_image&#039;]].&lt;br /&gt;
; allowall : Allow to select &#039;All file types&#039;, defaults to true. Does not apply with onlytypes are set.&lt;br /&gt;
; allowunknown : Skip implicit validation against the list of known file types.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;doctypes&#039;, get_string(&#039;doctypes&#039;, &#039;tool_myplugin&#039;), [&#039;onlytypes&#039; =&amp;gt; [&#039;document&#039;], &#039;allowunknown&#039; =&amp;gt; true]);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==addGroup==&lt;br /&gt;
A &#039;group&#039; in formslib is just a group of elements that will have a label and will be included on one line. &lt;br /&gt;
&lt;br /&gt;
For example typical code to include a submit and cancel button on the same line : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;cancel&#039;, get_string(&#039;cancel&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You use the same arguments for createElement as you do for addElement. Any label for the element in the third argument is normally ignored (but not in the case of the submit buttons above where the third argument is not for a label but is the text for the button).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a bad example (don&#039;t do this for real, use the &#039;optional&#039; =&amp;gt; true option of the date element): putting a date_selector (which is itself a group of elements) and a checkbox on the same line, note that you can disable every element in the group using the group name &#039;availablefromgroup&#039; but it doesn&#039;t disable the controlling element the &#039;availablefromenabled&#039; checkbox:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$availablefromgroup=array();&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;date_selector&#039;, &#039;availablefrom&#039;, &#039;&#039;);&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;availablefromenabled&#039;, &#039;&#039;, get_string(&#039;enable&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($availablefromgroup, &#039;availablefromgroup&#039;, get_string(&#039;availablefromdate&#039;, &#039;data&#039;), &#039;&amp;amp;nbsp;&#039;, false);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;availablefromgroup&#039;, &#039;availablefromenabled&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you want to put a group inside another array so that you can repeat items, use createElement instead of addGroup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* By default, groups modify the names of elements inside them by appending a number. This is often unhelpful, for example if you want to use disabledIf on the element. To prevent this behaviour, set the last parameter to false when creating a group.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems, null, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==addRule==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;elementname&#039;, get_string(&#039;error&#039;), &#039;rule type&#039;, &#039;extraruledata&#039;, &#039;server&#039;(default), false, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first param(element) is an element name and second(message) is the error message that will be displayed to the user.&lt;br /&gt;
The third parameter(type) is the type of rule. The fourth param(format) is used for extra data needed with some rules such as minlength and regex. The fifth parameter(validation) validates input data on server or client side, if validation is done on client side then it will be checked on the server side as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 * @param    string     $element       Form element name&lt;br /&gt;
 * @param    string     $message       Message to display for invalid data&lt;br /&gt;
 * @param    string     $type          Rule type, use getRegisteredRules() to get types&lt;br /&gt;
 * @param    string     $format        (optional)Required for extra rule data&lt;br /&gt;
 * @param    string     $validation    (optional)Where to perform validation: &amp;quot;server&amp;quot;, &amp;quot;client&amp;quot;&lt;br /&gt;
 * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?&lt;br /&gt;
 * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Common Rule Types&#039;&#039;&#039;&lt;br /&gt;
* required &lt;br /&gt;
* maxlength&lt;br /&gt;
* minlength&lt;br /&gt;
* rangelength&lt;br /&gt;
* email&lt;br /&gt;
* regex&lt;br /&gt;
* lettersonly&lt;br /&gt;
* alphanumeric&lt;br /&gt;
* numeric&lt;br /&gt;
* nopunctuation&lt;br /&gt;
* nonzero&lt;br /&gt;
* callback&lt;br /&gt;
* compare&lt;br /&gt;
===Server side and Client side===&lt;br /&gt;
In case you use the &#039;&#039;Client side&#039;&#039; validation option, you can mainly check for an empty or not input field. unless you write some &#039;&#039;Client side&#039;&#039; code which will probably be JavaScript functions to verify the data inside the input fields before it is submitted to the server. It could save some time if those functions are short, simple and quick to compute.&lt;br /&gt;
In case you need a more complex validation checks which relay on Moodle&#039;s internal PHP libraries (or other/external PHP libraries) you better use the &#039;&#039;Server side&#039;&#039; validation checks. Where you can query the DB, write complex PHP validation functions and much much more, that are not available (easily) when using JavaScript on the client&#039;s side.&lt;br /&gt;
==addHelpButton==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;api_key_field&#039;, &#039;api_key&#039;, &#039;block_extsearch&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The following parameters are expected:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param $elementname The name of the form element to add the help button for&lt;br /&gt;
 * @param $identifier The identifier for the help string and its title (see below)&lt;br /&gt;
 * @param $component The component name to look for the help string in&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# get_string($identifier, $component) // The title of the help page&lt;br /&gt;
# get_string(&amp;quot;{$identifier}_help&amp;quot;, $component) // The content of the help page&lt;br /&gt;
So you will need to have &#039;&#039;&#039;$identifier&#039;&#039;&#039; and &#039;&#039;&#039;{$identifier}_help&#039;&#039;&#039; defined in order for the help button to be created properly. For example the multiple choice question editing form has a button for shuffling the answers. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;shuffleanswers&#039;, &#039;shuffleanswers&#039;, &#039;qtype_multichoice&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and so the language file includes the strings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers&#039;] = &#039;Shuffle the choices?&#039;; &lt;br /&gt;
$string[&#039;shuffleanswers_help&#039;] = &#039;If enabled,.....&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also add the language string like&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers_link&#039;] = &#039;question/shuffleanswers&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to add a link to more help on Moodle docs. See [[String_API]] for more information about help icons.&lt;br /&gt;
==setDefault==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), $grades);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;grade&#039;, array(&#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), &#039;exercise&#039;));&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;grade&#039;, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Set the default of the form value with setDefault($elementname, $value); where elementname is the elementname whose default you want to set and $value is the default to set. We set the defaults for the form in definition(). This default is what is used if no data is loaded into the form with set_data(); eg. on display of the form for an &#039;add&#039; rather than &#039;update&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;desc&#039;, get_string(&#039;description&#039;));     &lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;desc&#039;, array(&#039;text&#039;=&amp;gt;$defaulttext));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that when setting the default for an editor element you must use an array to define the default &amp;quot;text&amp;quot; value as shown above.&lt;br /&gt;
==disabledIf==&lt;br /&gt;
For any element or groups of element in a form you can conditionally disable the group or individual element depending on conditions.&lt;br /&gt;
&lt;br /&gt;
You can use $mform-&amp;gt;disabledIf($elementName, $dependentOn, $condition = &#039;notchecked&#039;, $value=&#039;1&#039;)&lt;br /&gt;
* elementname can be a group. If you specify a group all elements in the group will be disabled (if dependentOn is in elementname group that is ignored and not disabled). These are the element names you&#039;ve used as the second argument in addElement or addGroup.&lt;br /&gt;
* dependentOn is the actual name of the element as it will appear in html. This can be different to the name used in addGroup particularly but also addElement where you&#039;re adding a complex element like a date_selector. Check the html of your page. You typically make the depedentOn a checkbox or select box.&lt;br /&gt;
* $condition will be &#039;notchecked&#039;, &#039;checked&#039;, &#039;noitemselected&#039;, &#039;eq&#039;, &#039;in&#039; or, if it is anything else, we test for &#039;neq&#039;.&lt;br /&gt;
** If $condition is &#039;eq&#039; or &#039;neq&#039; then we check the value of the dependentOn field and check for equality (==) or nonequality (!=) in js&lt;br /&gt;
** If $condition is &#039;checked&#039; or &#039;notchecked&#039; then we check to see if a checkbox is checked or not.&lt;br /&gt;
** If $condition is &#039;in&#039; then we check to see if a selected item is in the given list or not. (This was introduced in Moodle 2.7+)&lt;br /&gt;
** If $condition is &#039;noitemselected&#039; then we check to see whether nothing is selected in a dropdown list.&lt;br /&gt;
Examples:&lt;br /&gt;
 // Disable my control unless a checkbox is checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control if a checkbox &#039;&#039;&#039;is&#039;&#039;&#039; checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;, &#039;checked&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control when a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;eq&#039;, 42);&lt;br /&gt;
&lt;br /&gt;
 // Disable my control unless a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;neq&#039;, 42);&lt;br /&gt;
The possible choices here are in the dependency manager in lib/form/form.js.&lt;br /&gt;
===A tricky case===&lt;br /&gt;
You need to take care with disabledIf if you plan to use it with groups of checkboxes.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have a group of 5 checkboxes and you want to enable a depending item such as a drop down menu only when the first and the last checkboxes are selected.&lt;br /&gt;
&lt;br /&gt;
To fix ideas:&lt;br /&gt;
&lt;br /&gt;
If the selection in the checkboxes group is:&lt;br /&gt;
 mycheck_01 == 1&lt;br /&gt;
 mycheck_02 == 0&lt;br /&gt;
 mycheck_03 == 0&lt;br /&gt;
 mycheck_04 == 0&lt;br /&gt;
 mycheck_05 == 1&lt;br /&gt;
the depending item must be enabled while ANY OTHER COMBINATION must disable the drop down menu.&lt;br /&gt;
&lt;br /&gt;
The following code will, apparently, fail:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In fact, once you get the drop down menu enabled, you are free to unselect mycheck_01 whilst still having the depending item enabled.&lt;br /&gt;
This apparent bug occurs because a non-checked checkbox behaves like a non existing mform element. So the js code will not find the element &amp;quot;mycheck_01&amp;quot; and will not apply the corresponding rule.&lt;br /&gt;
&lt;br /&gt;
A working solution for this kind of issue seems to be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;notchecked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;notchecked&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To see a failing example as the one described, try the attachments provided in MDL-38975. See also in MDL-38975 for the working solution in action with modifications suggested by Eloy.&lt;br /&gt;
==hideIf==&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
For any element or groups of element in a form you can conditionally hide the group or individual element depending on conditions.&lt;br /&gt;
This uses the same syntax as disabledIf just with hideIf instead.&lt;br /&gt;
==setType==&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned. These should be used for get parameters such as id, course etc. which are used to load a page and also with setType(); method. Every form element should have a type specified except select, radio box and checkbox elements, these elements do a good job of cleaning themselves (only specified options are allowed as user input).&lt;br /&gt;
===Most Commonly Used PARAM_* Types===&lt;br /&gt;
These are the most commonly used PARAM_* types and their proper uses. More types can be seen in moodlelib.php starting around line 100. For the full list, see the file lib/moodlelib.php.&lt;br /&gt;
* PARAM_CLEAN is deprecated and you should try to use a more specific type.&lt;br /&gt;
* PARAM_TEXT should be used for cleaning data that is expected to contain multi-lang content. It will strip all html tags. But will still let tags for multilang support through.&lt;br /&gt;
* PARAM_NOTAGS should be used for cleaning data that is expected to be plain text. It will strip *all* html type tags. It will *not* let tags for multilang support through. This should be used for instance for email addresses where no multilang support is appropriate.&lt;br /&gt;
* PARAM_RAW means no cleaning whatsoever, it is used mostly for data from the html editor. Data from the editor is later cleaned before display using format_text() function. PARAM_RAW can also be used for data that is validated by some other way or printed by p() or s().&lt;br /&gt;
* PARAM_INT should be used for integers. PARAM_FLOAT is also available for decimal numbers but is not recommended for user input since it does not work for languages that use , as a decimal separator.&lt;br /&gt;
&lt;br /&gt;
These types are deprecated:&lt;br /&gt;
* PARAM_CLEAN obsoleted, please use a more specific type of parameter. @deprecated since 2.0&lt;br /&gt;
* PARAM_ACTION deprecated alias for PARAM_ALPHA use for various actions in forms and urls. Use PARAM_ALPHANUMEXT instead.&lt;br /&gt;
&lt;br /&gt;
==disable_form_change_checker==&lt;br /&gt;
By default, any Moodle form will pop-up an &amp;quot;Are you sure?&amp;quot; alert if you make some changes and then try to leave the page without saving. Occasionally, that is undesirable, in which case you can call&lt;br /&gt;
 $mform-&amp;gt;disable_form_change_checker()&lt;br /&gt;
&lt;br /&gt;
==RTL support==&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
As of Moodle 3.2, some form elements have been refined to better support right-to-left languages. In RTL, most fields should not have their direction flipped, a URL, a path to a file, a number, ... are always displayed LTR. Input fields and text areas now will best guess whether they should be forced to be displayed in LTR based on the PARAM type associated with it. You can call:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setForceLtr(&#039;name&#039;, true/false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
on some form fields (like &#039;text&#039;) to manually set the value, and for directionality.&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
* [http://www.midnighthax.com/quickform.php PEAR HTML QuickForm Getting Started Guide] by Keith Edmunds of Midnighthax.com&lt;br /&gt;
* [http://pear.php.net/manual/en/package.html.html-quickform.php PEAR::HTML_QuickForm manual]&lt;br /&gt;
[[Category:Formslib]]&lt;br /&gt;
[[Category:Interfaces]]&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=63910</id>
		<title>lib/formslib.php Form Definition</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=63910"/>
		<updated>2023-06-05T13:06:13Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* text */ Remove lines which presumably applied to &amp;#039;format&amp;#039; element removed in Moodle 2.4 (MDL-31294)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Formslib}}&lt;br /&gt;
== &#039;&#039;definition()&#039;&#039; ==&lt;br /&gt;
The definition of the elements to be included in the form, their &#039;types&#039; (PARAM_*), helpbuttons included, etc. is all included in a function you must define in your class.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;definition()&#039;&#039; is used to define the elements in the form and &#039;&#039;&#039;this definition will be used for validating data submitted as well as for printing the form.&#039;&#039;&#039; For select and checkbox type elements only data that could have been selected will be allowed. And only data that corresponds to a form element in the definition will be accepted as submitted data.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;definition()&#039;&#039; should include all elements that are going to be used on form, some elements may be removed or tweaked later in &#039;&#039;definition_after_data()&#039;&#039;. Please do not create conditional elements in &#039;&#039;definition()&#039;&#039;, the definition() should not directly depend on the submitted data.&lt;br /&gt;
&lt;br /&gt;
Note that the definition function is called when the form class is instantiated. There is no option to (say) manipulate data in the class (that may affect the rendering of the form) between instantiating the form and calling any other methods. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;libdir/formslib.php&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
class simplehtml_form extends moodleform {&lt;br /&gt;
&lt;br /&gt;
    function definition() {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
       &lt;br /&gt;
        $mform = $this-&amp;gt;_form; // Don&#039;t forget the underscore! &lt;br /&gt;
&lt;br /&gt;
        $mform-&amp;gt;addElement()... // Add elements to your form&lt;br /&gt;
            ...&lt;br /&gt;
    }                           // Close the function&lt;br /&gt;
}                               // Close the class&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
===Passing parameters to the Form===&lt;br /&gt;
The constructor for &#039;&#039;moodleform&#039;&#039; allows a number of parameters including one (&#039;&#039;$customdata&#039;&#039;) to permit an array of arbitrary data to be passed to your form. &lt;br /&gt;
&lt;br /&gt;
For example, you can pass the data &amp;quot;$email&amp;quot; and &amp;quot;$username&amp;quot; to the Form&#039;s class for use inside (say) the definition.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform_simple = new simplehtml_form( null, array(&#039;email&#039;=&amp;gt;$email, &#039;username&#039;=&amp;gt;$username ) );&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
(the first parameter is $action, &#039;&#039;null&#039;&#039; will cause the form action to be determined automatically)&lt;br /&gt;
&lt;br /&gt;
Secondly, inside the form definition you can use those parameters to set the default values to some of the form&#039;s fields&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
 $mform-&amp;gt;addElement(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;), &#039;maxlength=&amp;quot;100&amp;quot; size=&amp;quot;25&amp;quot; &#039;);&lt;br /&gt;
 $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);&lt;br /&gt;
 $mform-&amp;gt;addRule(&#039;email&#039;, get_string(&#039;missingemail&#039;), &#039;required&#039;, null, &#039;server&#039;);&lt;br /&gt;
 // Set default value by using a passed parameter&lt;br /&gt;
 $mform-&amp;gt;setDefault(&#039;email&#039;,$this-&amp;gt;_customdata[&#039;email&#039;]);&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Use Fieldsets to group Form Elements==&lt;br /&gt;
You use code like this to open a fieldset with a &#039;&#039;legend&#039;&#039;. &amp;lt;br /&amp;gt;&lt;br /&gt;
(&#039;&#039;&#039;Note&#039;&#039;&#039;: Some themes turn off legends on admin setting pages by using CSS: &amp;lt;nowiki&amp;gt;#adminsettings legend {display:none;}&amp;lt;/nowiki&amp;gt;.)&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;header&#039;, &#039;nameforyourheaderelement&#039;, get_string(&#039;titleforlegened&#039;, &#039;modulename&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can&#039;t yet nest these visible fieldsets unfortunately. But in fact groups of elements are wrapped in invisible fieldsets.&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.5}}&lt;br /&gt;
Since Moodle 2.5 fieldsets without any required fields are collapsed by default. To display these fieldsets on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To close a fieldset on page load, use:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
 $mform-&amp;gt;setExpanded(&#039;foo&#039;, false)&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You close a fieldset with moodle_form&#039;s closeHeaderBefore method. You tell closeHeaderBefore the element before you wish to end the fieldset. A fieldset is automatically closed if you open a new one. You need to use this code only if you want to close a fieldset and the subsequent form elements are not to be enclosed by a visible fieldset (they are still enclosed with an invisibe one with no legend) :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;closeHeaderBefore(&#039;buttonar&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==addElement==&lt;br /&gt;
Use the addElement method to add an element to a form. The first few arguments are always the same. The first param is the type of the element to add. The second is the elementname to use which is normally the html name of the element in the form. The third is often the text for the label for the element.&lt;br /&gt;
&lt;br /&gt;
Some examples are below :&lt;br /&gt;
=== button ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;button&#039;, &#039;intro&#039;, get_string(&amp;quot;buttonlabel&amp;quot;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A button element. If you want a submit or cancel button see &#039;submit&#039; element.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== autocomplete ===&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
Available since Moodle 3.1&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$searchareas = \core_search\manager::get_search_areas_list(true);                                                           &lt;br /&gt;
$areanames = array();                                                                                                       &lt;br /&gt;
foreach ($searchareas as $areaid =&amp;gt; $searcharea) {                                                                          &lt;br /&gt;
    $areanames[$areaid] = $searcharea-&amp;gt;get_visible_name();                                                                  &lt;br /&gt;
}                                                                                                                           &lt;br /&gt;
$options = array(                                                                                                           &lt;br /&gt;
    &#039;multiple&#039; =&amp;gt; true,                                                  &lt;br /&gt;
    &#039;noselectionstring&#039; =&amp;gt; get_string(&#039;allareas&#039;, &#039;search&#039;),                                                                &lt;br /&gt;
);         &lt;br /&gt;
$mform-&amp;gt;addElement(&#039;autocomplete&#039;, &#039;areaids&#039;, get_string(&#039;searcharea&#039;, &#039;search&#039;), $areanames, $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The autocomplete element is an advanced form element that supports server-side searching - or simple filtering of a predefined list of options. Some benefits of using this form element are that it handles very large datasets extremely well - it has great accessibility built in - and it gives a good user experience. If you have so much data you need to build pagination into a page - you could probably come up with a better design using this. The simplest way to use it is compatible with the standard &#039;select&#039; form element. You give it a list of options and some parameters to configure how it behaves. The valid parameters for this simple mode of operation are:&lt;br /&gt;
* multiple (boolean - default false) - Allow more than one selected item. The data coming from the form will be an array in this case.&lt;br /&gt;
[[image:autocomplete_multiple2.png|center|thumb|alt=autocomplete with multiple option|autocomplete with multiple option.]]&lt;br /&gt;
* noselectionstring (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to display when nothing is selected.&lt;br /&gt;
* showsuggestions (boolean - default true) - Do not show the list of suggestions when the user starts typing.&lt;br /&gt;
* placeholder (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - The text to show in the search box when it is empty.&lt;br /&gt;
* casesensitive (boolean - default false) - Is the search case sensitive ?&lt;br /&gt;
* tags (boolean - default false) - This changes the behaviour so that the user can create new valid entries in the list by typing them and pressing enter.&lt;br /&gt;
* ajax (string - default &amp;lt;nowiki&amp;gt;&#039;&#039;&amp;lt;/nowiki&amp;gt;) - This string is the name of an AMD module that can fetch and format results.&lt;br /&gt;
* valuehtmlcallback - For use with the AJAX option, so that it can format the initial value of the form field (available since Moodle 3.5)&lt;br /&gt;
More explanation on the &#039;ajax&#039; option. This should be the name of an AMD module that implements 2 functions:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;javascript&amp;quot;&amp;gt;&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Source of data for Ajax element.&lt;br /&gt;
 *&lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.&lt;br /&gt;
 * @param {String} query The query string.                        &lt;br /&gt;
 * @param {Function} callback A callback function receiving an array of results.&lt;br /&gt;
 * @param {Function} failure A callback function to be called in case of failure, receiving the error message.&lt;br /&gt;
 * @return {Void}                                                                                                           &lt;br /&gt;
*/                                                                                                                         &lt;br /&gt;
transport: function(selector, query, callback, failure) ...&lt;br /&gt;
&lt;br /&gt;
/**                                                                                                                         &lt;br /&gt;
 * Process the results for auto complete elements.                                                                          &lt;br /&gt;
 *                                                                                                                          &lt;br /&gt;
 * @param {String} selector The selector of the auto complete element.                                                      &lt;br /&gt;
 * @param {Array} results An array or results.                                                                              &lt;br /&gt;
 * @return {Array} New array of results.                                                                                    &lt;br /&gt;
 */                                                                                                                         &lt;br /&gt;
processResults: function(selector, results)...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A good example is here: [https://github.com/moodle/moodle/blob/master/admin/tool/lp/amd/src/frameworks_datasource.js admin/tool/lp/amd/src/frameworks_datasource.js]&lt;br /&gt;
&lt;br /&gt;
The &#039;valuehtmlcallback&#039; function is needed when an AJAX-supporting form field has an initial value that needs special rendering, similar to how the AJAX code would render it when the user changes it dynamically. For example, if the field contains user ids and its initial value is &#039;1,2&#039; then you want it to use the rendered HTML display for each value (probably a user&#039;s name and picture), not just display those numbers. Here is an example, from /search/classes/output/form/search.php:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
&#039;valuehtmlcallback&#039; =&amp;gt; function($value) {&lt;br /&gt;
    global $DB, $OUTPUT;&lt;br /&gt;
    $user = $DB-&amp;gt;get_record(&#039;user&#039;, [&#039;id&#039; =&amp;gt; (int)$value], &#039;*&#039;, IGNORE_MISSING);&lt;br /&gt;
    if (!$user || !user_can_view_profile($user)) {&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
    $details = user_get_user_details($user);&lt;br /&gt;
    return $OUTPUT-&amp;gt;render_from_template(&lt;br /&gt;
        &#039;core_search/form-user-selector-suggestion&#039;, $details);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The Mustache template used here is the same as the one used by the AJAX code when the field is changed dynamically.&lt;br /&gt;
&lt;br /&gt;
When using the ajax option in an mform with validation etc - it is recommended to sub-class the php class &amp;quot;MoodleQuickForm_autocomplete&amp;quot; so that you can provide a list of name and&lt;br /&gt;
values to populate the form element if the form is re-displayed due to a validation error. An example is [https://github.com/moodle/moodle/blob/MOODLE_31_STABLE/admin/tool/lp/classes/form/framework_autocomplete.php admin/tool/lp/classes/form/framework_autocomplete.php].&lt;br /&gt;
&lt;br /&gt;
We have provided several useful subclasses of this form element already that are simple to use (course and tags).&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt; &lt;br /&gt;
    // Course example.&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;multiple&#039; - boolean multi select                                                                      &lt;br /&gt;
    //                       &#039;exclude&#039; - array or int, list of course ids to never show                                             &lt;br /&gt;
    //                       &#039;requiredcapabilities&#039; - array of capabilities. Uses ANY to combine them.                              &lt;br /&gt;
    //                       &#039;limittoenrolled&#039; - boolean Limits to enrolled courses.                                                &lt;br /&gt;
    //                       &#039;includefrontpage&#039; - boolean Enables the frontpage to be selected.  &lt;br /&gt;
    $options = array(&#039;multiple&#039; =&amp;gt; true, &#039;includefrontpage&#039; =&amp;gt; true);                                                           &lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course&#039;, &#039;mappedcourses&#039;, get_string(&#039;courses&#039;), $options); &lt;br /&gt;
&lt;br /&gt;
    // Tags&lt;br /&gt;
    //  Valid options are:                                                                                     &lt;br /&gt;
    //                       &#039;showstandard&#039; - boolean One of the core_tag_tag constants to say which tags to display&lt;br /&gt;
    //                       &#039;component&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    //                       &#039;itemtype&#039; - string The component name and itemtype define the tag area&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;tags&#039;, &#039;interests&#039;, get_string(&#039;interestslist&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;user&#039;, &#039;component&#039; =&amp;gt; &#039;core&#039;));     &lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== checkbox ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a simple checkbox. The third parameter for this element is the label to display on the left side of the form. You can also supply a string as a fourth parameter to specify a label that will appear on the right of the element. Checkboxes and radio buttons can be grouped and have individual labels on their right.&lt;br /&gt;
&lt;br /&gt;
You can have a 5th parameter $attributes, as on other elements.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;BEWARE:&#039;&#039;&#039; Unchecked checkboxes return nothing at all (as if they didn&#039;t exist). This can surprise the unwary. You may wish to use advcheckbox instead, which does return a value when not checked. &#039;Advcheckbox&#039; eliminates this problem. &lt;br /&gt;
==== advcheckbox ====&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, &#039;ratingtime&#039;, get_string(&#039;ratingtime&#039;, &#039;forum&#039;), &#039;Label displayed after checkbox&#039;, array(&#039;group&#039; =&amp;gt; 1), array(0, 1));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Similar to the checkbox above, but with some important improvements:&lt;br /&gt;
# The (optional) 5th parameter is a normal $attributes array, normally used to set HTML attributes for the &amp;lt;input&amp;gt; element. However, a special value of &#039;group&#039; can be given, which will add a class name to the element, and enable its grouping for a [[lib/formslib.php_add_checkbox_controller|checkbox controller]]&lt;br /&gt;
#The (optional) 6th parameter is an array of values that will be associated with the checked/unchecked state of the checkbox. With a normal checkbox you cannot choose that value, and in fact an unchecked checkbox will not even be sent with the form data.&lt;br /&gt;
#It returns a 0 value when unchecked. Compare with the ordinary checkbox which does not return anything at all.&lt;br /&gt;
=== choosecoursefile ===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;choosecoursefile&#039;, &#039;mediafile&#039;, get_string(&#039;mediafile&#039;, &#039;lesson&#039;), array(&#039;courseid&#039;=&amp;gt;$COURSE-&amp;gt;id));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Choose a file from the course files area. The fourth option is a list of options for the element. &lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note: This has been superceded by [[#filepicker|filepicker]] in Moodle 2.&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&#039;courseid&#039; =&amp;gt;null,  //if it is null (default then use global $COURSE&lt;br /&gt;
      &#039;height&#039;   =&amp;gt;500,   // height of the popup window&lt;br /&gt;
      &#039;width&#039;    =&amp;gt;750,   // width of the popup window&lt;br /&gt;
      &#039;options&#039;  =&amp;gt;&#039;none&#039;); //options string for the pop up window &lt;br /&gt;
                          //eg. &#039;menubar=0,location=0,scrollbars,resizable&#039;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;maxlength&#039; =&amp;gt; 255, &#039;size&#039; =&amp;gt; 48)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the maxlength / size of the text box (note size will default to 48 if not specified)&lt;br /&gt;
&lt;br /&gt;
Finally, as this element is a group containing two elements (button + value), you can add validation rules by using the &#039;&#039;&#039;addGroupRule()&#039;&#039;&#039; method in this (complex) way:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;elementname&#039;, array(&#039;value&#039; =&amp;gt; array(array(list, of, rule, params, but, fieldname))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Where: &#039;&#039;&#039;&amp;quot;elementname&amp;quot;&#039;&#039;&#039; is the name of the choosecoursefile group element, &#039;&#039;&#039;&amp;quot;value&amp;quot;&#039;&#039;&#039; is the name of the text field within the group and the &#039;&#039;&#039;&amp;quot;list, of, addrule, params, but, fieldname&amp;quot;&#039;&#039;&#039; is exactly that, the list of fields in the normal addRule() function but ommiting the first one, the fieldname.&lt;br /&gt;
&lt;br /&gt;
For example, the [http://cvs.moodle.org/moodle/mod/resource/type/file/resource.class.php?view=markup file/url resource type], uses one &amp;quot;choosecoursefile&amp;quot; element, and it controls the maximum length of the field (255) with this use of addGroupRule():&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;$mform-&amp;gt;addGroupRule(&#039;reference&#039;, array(&#039;value&#039; =&amp;gt; array(array(get_string(&#039;maximumchars&#039;, &#039;&#039;, 255), &#039;maxlength&#039;, 255, &#039;client&#039;))));&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
=== date_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_selector&#039;, &#039;assesstimefinish&#039;, get_string(&#039;to&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a date selector. You can select a Day, Month and Year using a group of select boxes. The fourth param here is an array of options. The defaults for the options are :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;optional&#039;  =&amp;gt; false&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. You can supply a fifth param of attributes here as well.&lt;br /&gt;
=== date_time_selector ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;date_time_selector&#039;, &#039;assesstimestart&#039;, get_string(&#039;from&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This is a group of select boxes to select a date (Day Month and Year) and time (Hour and Minute). When submitted, submitted data is processed and a timestamp is passed to $form-&amp;gt;get_data(); the fourth param here is an array of options. The defaults for the options are:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;startyear&#039; =&amp;gt; 1970, &lt;br /&gt;
    &#039;stopyear&#039;  =&amp;gt; 2020,&lt;br /&gt;
    &#039;timezone&#039;  =&amp;gt; 99,&lt;br /&gt;
    &#039;step&#039;      =&amp;gt; 5,&lt;br /&gt;
    &#039;optional&#039; =&amp;gt; false,&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can override these defaults by supplying an array as fourth param with one or more keys with a value to override the default. Setting &#039;optional&#039; to true adds an &#039;enable&#039; checkbox to the selector. You can supply a fifth param of attributes here as well.&lt;br /&gt;
===duration===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;duration&#039;, &#039;timelimit&#039;, get_string(&#039;timelimit&#039;, &#039;quiz&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This field type lets the user input an interval of time. It comprises a text field, where you can type a number, and a dropdown for selecting a unit (days, hours, minutes or seconds). When submitted the value is converted to a number of seconds.&lt;br /&gt;
&lt;br /&gt;
You can add a fourth parameter to give options. At the moment the only option supported is here is an array of options. The defaults for the options is:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;optional&#039; =&amp;gt; true)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also pass an optional 5th parameter of attributes, as for other elements. The most useful way of using that is something like &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;array(&#039;size&#039; =&amp;gt; 5)&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to control the size of the text box.&lt;br /&gt;
=== editor ===&lt;br /&gt;
This replaces the old htmleditor field type. It allows the user to enter rich text content in a variety of formats.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;fieldname&#039;, get_string(&#039;labeltext&#039;, &#039;langfile&#039;));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;fieldname&#039;, PARAM_RAW);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
NOTE: It won&#039;t work properly without the setType() as shown.&lt;br /&gt;
&lt;br /&gt;
If you would like to let the user use the filepicker to upload images etc. that are used in the content, then see [[Using_the_File_API_in_Moodle_forms]].&lt;br /&gt;
&lt;br /&gt;
You can supply a fifth param to htmleditor of an array of options that are mostly related to file handling:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
array(&lt;br /&gt;
    &#039;subdirs&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxbytes&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;maxfiles&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;changeformat&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;context&#039;=&amp;gt;null,&lt;br /&gt;
    &#039;noclean&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;trusttext&#039;=&amp;gt;0,&lt;br /&gt;
    &#039;enable_filemanagement&#039; =&amp;gt; true);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The option &#039;enable_filemanagement&#039; will display the file management button on true and remove it on false.&lt;br /&gt;
&lt;br /&gt;
To save the data if you don&#039;t care about files:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$text     = $formdata-&amp;gt;fieldname[&#039;text&#039;];&lt;br /&gt;
$format   = $formdata-&amp;gt;fieldname[&#039;format&#039;];&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Note: Because the text editor might be &amp;quot;Atto&amp;quot; (depending on user preferences) and Atto has an &amp;quot;autosave&amp;quot; feature - it requires that the combination of $PAGE-&amp;gt;url and this elementid are unique. If not, the autosaved text for a different form may be restored into this form.&lt;br /&gt;
=== file ===&lt;br /&gt;
File upload input box with browse button. In the form definition type&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
after form submission and validation use&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If there is no requirement to save the file, you can read the file contents directly into a string as follows...&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    $mform-&amp;gt;get_file_content(&#039;attachment&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you need advanced settings such as required file, different max upload size or name of uploaded file&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0, true, true, false));&lt;br /&gt;
            $mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
            $mform-&amp;gt;addRule(&#039;attachment&#039;, null, &#039;required&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
    $newfilename = $mform-&amp;gt;get_new_filename();&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
When porting old code it is also possible to use the upload manager directly for processing of uploaded files.&lt;br /&gt;
&lt;br /&gt;
Please note that if using set_upload_manager() it must be before addElement(&#039;file&#039;,..).&lt;br /&gt;
&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
File uploading was rewritten in 2.0. Please see inline docs for now. This page will be updated when the new API stabilises.&lt;br /&gt;
===filepicker===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
General replacement of &#039;&#039;file&#039;&#039; element.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null, array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See also [[Using the File API in Moodle forms]]&lt;br /&gt;
=== hidden ===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;hidden&#039;, &#039;reply&#039;, &#039;yes&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
A hidden element. Set the element name (in this case &#039;&#039;&#039;reply&#039;&#039;&#039;) to the stated value (in this case &#039;&#039;&#039;yes&#039;&#039;&#039;).&lt;br /&gt;
=== html ===&lt;br /&gt;
You can add arbitrary HTML to your Moodle form:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;html&#039;, &#039;&amp;lt;div class=&amp;quot;qheader&amp;quot;&amp;gt;&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See [http://moodle.org/mod/forum/discuss.php?d=126935 &amp;quot;Question: Can I put a moodleform inside a table td?&amp;quot;] for a concrete example.&lt;br /&gt;
=== htmleditor &amp;amp; format ===&lt;br /&gt;
These elements are now deprecated. Please use the [[#editor|editor]] field type instead.&lt;br /&gt;
===modgrade===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modgrade&#039;, &#039;scale&#039;, get_string(&#039;grade&#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade for any activity module. The fourth argument is whether to include an option for no grade which has a value 0. This select box does include scales. The default is true, include no grade option.&lt;br /&gt;
&lt;br /&gt;
A helpbutton is automatically added.&lt;br /&gt;
===modvisible===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;modvisible&#039;, &#039;visible&#039;, get_string(&#039;visible&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a custom element for selecting a grade visibility in an activity mod update form.&lt;br /&gt;
===password===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;password&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element. Fourth param is an array or string of attributes.&lt;br /&gt;
===passwordunmask===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;passwordunmask&#039;, &#039;password&#039;, get_string(&#039;label&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A password element with option to show the password in plaintext. Fourth param is an array or string of attributes.&lt;br /&gt;
=== radio ===&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$radioarray=array();&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;yes&#039;), 1, $attributes);&lt;br /&gt;
$radioarray[] = $mform-&amp;gt;createElement(&#039;radio&#039;, &#039;yesno&#039;, &#039;&#039;, get_string(&#039;no&#039;), 0, $attributes);&lt;br /&gt;
$mform-&amp;gt;addGroup($radioarray, &#039;radioar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Second param names the radio button and should be the same for each button in the group in order to toggle correctly. Third param would be the label for the form element but is generally ignored as this element will always be in a group which has it&#039;s own label. Fourth param is a string, a label to be displayed on the right of the element. The fifth is the value for this radio button. $attributes can be a string or an array of attributes.&lt;br /&gt;
&lt;br /&gt;
It is possible to add help to individual radio buttons but this requires a custom template to be defined for the group elements. See MDL-15571.&lt;br /&gt;
&lt;br /&gt;
Since 2.3 it cannot be statically called anymore, so we need to call createElement from $mform reference.&lt;br /&gt;
==== setDefault ====&lt;br /&gt;
To set the default for a radio button group as above use the following :&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;yesno&#039;, 0);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This would make the default &#039;no&#039;.&lt;br /&gt;
===select===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;type&#039;, get_string(&#039;forumtype&#039;, &#039;forum&#039;), $FORUM_TYPES, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The fourth param for this element is an array of options for the select box. The keys are the values for the option and the value of the array is the text for the option. The fifth param $attributes is optional, see text element for description of attributes param.&lt;br /&gt;
&lt;br /&gt;
It is also possible to create a select with certain options disabled, using [http://stackoverflow.com/questions/2138089/how-can-i-use-quickform-to-add-disabled-select-options/2150275#2150275 this technique].&lt;br /&gt;
&lt;br /&gt;
You can set an &#039;onchange&#039; attribute when adding or creating the select element: &lt;br /&gt;
&lt;br /&gt;
$form-&amp;gt;addElement(&#039;select&#039;, &#039;iselTest&#039;, &#039;Test Select:&#039;, $arrayOfOptions, array(&#039;onchange&#039; =&amp;gt; &#039;javascript:myFunctionToDoSomething();&#039;));&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
====multi-select====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), array(&#039;red&#039;, &#039;blue&#039;, &#039;green&#039;), $attributes);&lt;br /&gt;
$select-&amp;gt;setMultiple(true);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
=====setSelected=====&lt;br /&gt;
To set the default selected item in a select element, you can use the &#039;setSelected&#039; method. The &#039;setSelected&#039; can either get a value or an array of values.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array(&lt;br /&gt;
    &#039;ff0000&#039; =&amp;gt; &#039;Red&#039;,&lt;br /&gt;
    &#039;00ff00&#039; =&amp;gt; &#039;Green&#039;,&lt;br /&gt;
    &#039;0000ff&#039; =&amp;gt; &#039;Blue&#039;&lt;br /&gt;
);&lt;br /&gt;
$select = $mform-&amp;gt;addElement(&#039;select&#039;, &#039;colors&#039;, get_string(&#039;colors&#039;), $options);&lt;br /&gt;
// This will select the colour blue.&lt;br /&gt;
$select-&amp;gt;setSelected(&#039;0000ff&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Or for multiple-selection:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$skillsarray = array(&lt;br /&gt;
    &#039;val1&#039; =&amp;gt; &#039;Skill A&#039;,&lt;br /&gt;
    &#039;val2&#039; =&amp;gt; &#039;Skill B&#039;,&lt;br /&gt;
    &#039;val3&#039; =&amp;gt; &#039;Skill C&#039;&lt;br /&gt;
);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;md_skills&#039;, get_string(&#039;skills&#039;, &#039;metadata&#039;), $skillsarray);&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setMultiple(true);&lt;br /&gt;
// This will select the skills A and B.&lt;br /&gt;
$mform-&amp;gt;getElement(&#039;md_skills&#039;)-&amp;gt;setSelected(array(&#039;val1&#039;, &#039;val2&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
However you probably don&#039;t want to do this. Instead you probably want to use setDefault, or set it using the form&#039;s setData method.&lt;br /&gt;
===selectyesno===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;maxbytes&#039;, get_string(&#039;maxattachmentsize&#039;, &#039;forum&#039;));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
If you want a yes / no select box this one automatically translates itself and has value 1 for yes and 0 for no.&lt;br /&gt;
===selectwithlink===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$options = array();&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;selectwithlink&#039;, &#039;scaleid&#039;, get_string(&#039;scale&#039;), $options, null, &lt;br /&gt;
    array(&#039;link&#039; =&amp;gt; $CFG-&amp;gt;wwwroot.&#039;/grade/edit/scale/edit.php?courseid=&#039;.$COURSE-&amp;gt;id, &#039;label&#039; =&amp;gt; get_string(&#039;scalescustomcreate&#039;)));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
select type element with options containing link&lt;br /&gt;
===static===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;description&#039;, &#039;exercise&#039;),&lt;br /&gt;
    get_string(&#039;descriptionofexercise&#039;, &#039;exercise&#039;, $COURSE-&amp;gt;students));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
This is a static element. It should be used with care if it is used to display a static piece of text with a label. The third param is the label and the fourth is the static text itself.&lt;br /&gt;
===submit, reset and cancel===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
//normally you use add_action_buttons instead of this code&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;reset&#039;, &#039;resetbutton&#039;, get_string(&#039;revert&#039;));&lt;br /&gt;
$buttonarray[] = $mform-&amp;gt;createElement(&#039;cancel&#039;);&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, &#039; &#039;, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A &#039;Submit&#039; type element is a submit type form element which will submit the form. A &#039;Reset&#039; will not submit the form but will reset any changes the user has made to form contents. A &#039;Cancel&#039; element cancels form submission. You need to have a branch in your code before you check for get_data() to check if submission has been cancelled with is_cancelled(); See the example on the usage page.&lt;br /&gt;
&lt;br /&gt;
You should name your submit and reset buttons &#039;submitbutton&#039; and &#039;resetbutton&#039; or something similar (not &#039;submit&#039; and &#039;reset&#039;). This avoids problems in JavaScript of collisions between form element names and names of JavaScript methods of the form object.&lt;br /&gt;
====add_action_buttons($cancel = true, $submitlabel=null);====&lt;br /&gt;
You will normally use this helper function which is a method of moodleform to add all the &#039;action&#039; buttons to the end of your form. A boolean parameter allow you to specify whether to include a cancel button and specify the label for your submit button (pass the result of get_string). Default for the submit button label is get_string(&#039;savechanges&#039;). Note the &#039;&#039;&#039;$this&#039;&#039;&#039; not &#039;&#039;&#039;$mform&#039;&#039;&#039;&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===text===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;text&#039;, &#039;name&#039;, get_string(&#039;forumname&#039;, &#039;forum&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
For a simple text input element. (For text labels, use the &#039;static&#039; element.) Your fourth parameter here can be a string or array of attributes for the text element. The following are equivalent :&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$attributes=&#039;size=&amp;quot;20&amp;quot;&#039;;&lt;br /&gt;
$attributes=array(&#039;size&#039;=&amp;gt;&#039;20&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Generally you are encouraged to use CSS instead of using attributes for styling.&lt;br /&gt;
&lt;br /&gt;
====RTL support====&lt;br /&gt;
{{Moodle 3.2}}&lt;br /&gt;
&lt;br /&gt;
As of Moodle 3.2, some form elements have been refined to better support right-to-left languages. In RTL, most fields should not have their direction flipped, a URL, a path to a file, a number, ... are always displayed LTR. Input fields and text areas now will best guess whether they should be forced to be displayed in LTR based on the PARAM type associated with it. You can call:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;setForceLtr(&#039;name&#039;, true/false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
on some form fields (like &#039;text&#039;) to manually set the value, and for directionality.&lt;br /&gt;
====float====&lt;br /&gt;
{{Moodle 3.7}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;float&#039;, &#039;defaultmark&#039;, get_string(&#039;defaultmark&#039;, &#039;question&#039;), $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use the float element if you want a text box to get a floating point number. This element automatically supports localised decimal separators. You don&#039;t need to use setType with the float element.&lt;br /&gt;
&lt;br /&gt;
===textarea===&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;textarea&#039;, &#039;introduction&#039;, get_string(&amp;quot;introtext&amp;quot;, &amp;quot;survey&amp;quot;), &#039;wrap=&amp;quot;virtual&amp;quot; rows=&amp;quot;20&amp;quot; cols=&amp;quot;50&amp;quot;&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A textarea element. If you want an htmleditor use htmleditor element. Fourth element here is a string or array of attributes.&lt;br /&gt;
===recaptcha===&lt;br /&gt;
{{Moodle 1.9}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;recaptcha&#039;, &#039;recaptcha_field_name&#039;, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Use this recaptcha element to reduce the spam risk in your forms. Third element here is a string or array of attributes. Take care to get an API key from http://recaptcha.net/api/getkey before using this element.&lt;br /&gt;
&lt;br /&gt;
To check whether recaptcha is enabled at site level use:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
if (!empty($CFG-&amp;gt;recaptchapublickey) &amp;amp;&amp;amp; !empty($CFG-&amp;gt;recaptchaprivatekey)) {&lt;br /&gt;
    //recaptcha is enabled&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===tags===&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;field_name&#039;, $lable, $options, $attributes);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Used for editing a list of tags, for example on a blog post.&lt;br /&gt;
&lt;br /&gt;
There is only one option available, &#039;display&#039;, which should be set to one of the contstants MoodleQuickForm_tags::ONLYOFFICIAL, NOOFFICIAL or DEFAULTUI. This controls whether the official tags are listed for easy selection, or a text area where arbitrary tags may be typed, or both. The default is both.&lt;br /&gt;
&lt;br /&gt;
The value should be set/returned as an array of tags.&lt;br /&gt;
===grading===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;grading&#039;, &#039;advancedgrading&#039;, get_string(&#039;grade&#039;).&#039;:&#039;, array(&#039;gradinginstance&#039; =&amp;gt; $gradinginstance));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Custom element for advanced grading plugins.&lt;br /&gt;
&lt;br /&gt;
When adding the &#039;grading&#039; element to the form, developer must pass an object of class gradingform_instance as $attributes[&#039;gradinginstance&#039;]. Otherwise an exception will be thrown.&lt;br /&gt;
===questioncategory===&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;questioncategory&#039;, &#039;category&#039;, get_string(&#039;category&#039;, &#039;question&#039;),&lt;br /&gt;
    array(&#039;contexts&#039;=&amp;gt;$contexts, &#039;top&#039;=&amp;gt;true, &#039;currentcat&#039;=&amp;gt;$currentcat, &#039;nochildrenof&#039;=&amp;gt;$currentcat));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates a drop down element to select a question category.&lt;br /&gt;
&lt;br /&gt;
Options are:&lt;br /&gt;
&#039;&#039;&#039;contexts&#039;&#039;&#039; - (required) context in which question appears&lt;br /&gt;
&#039;&#039;&#039;currentcat&#039;&#039;&#039; - (optional) course category&lt;br /&gt;
&#039;&#039;&#039;top&#039;&#039;&#039; - (optional) if true will put top categories on top&lt;br /&gt;
&#039;&#039;&#039;nochildrenof&#039;&#039;&#039; - (optional) Format categories into an indented list reflecting the tree structure&lt;br /&gt;
=== filetypes ===&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
Available since Moodle 3.4&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;allowedfiletypes&#039;, get_string(&#039;allowedfiletypes&#039;, &#039;tool_myplugin&#039;));&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Creates an input element allowing the user to specify file types for the given purpose. The typical scenario is a setting that allows the teacher define a list of allowed file types submitted by students.&lt;br /&gt;
&lt;br /&gt;
The element allows the user to either type the list of filetypes manually, or select the types from the list. Also supported is selecting the whole group of file types - such as &amp;quot;image&amp;quot;. The element integrates with the [[Core filetypes]] system so all default types and groups are presented, as well as those [[:en:Working with files#Site administration settings|defined locally by the admin]].&lt;br /&gt;
&lt;br /&gt;
As the list can be types in manually, the form processing code should always normalize it first via the provided utility methods:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$formdata = $mform-&amp;gt;get_data();&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$allowedfiletypes = $filetypesutil-&amp;gt;normalize_file_types($formdata-&amp;gt;allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
This always returns an array of recognized valid values. The original list can be separated by whitespace, end of lines, commas, colons and semicolons. During the normalization, values are converted to lowercase, empty valies and duplicates are removed. Glob evaluation is not supported.&lt;br /&gt;
&lt;br /&gt;
The normalization should also happen if the previously defined list had been saved to the database and re-read for actual usage. The normalization output value can be directly used as the accepted_types option for the filepicker.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$filetypesutil = new \core_form\filetypes_util();&lt;br /&gt;
$options[&#039;accepted_types&#039;] = $filetypesutil-&amp;gt;normalize_file_types($allowedfiletypes);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
By default, user input is validated against the list of known file types and groups. This validation can be disabled via options.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Supported options&#039;&#039;&#039;&lt;br /&gt;
; onlytypes : Allow selection from these file types only; for example [&#039;onlytypes&#039; =&amp;gt; [&#039;web_image&#039;]].&lt;br /&gt;
; allowall : Allow to select &#039;All file types&#039;, defaults to true. Does not apply with onlytypes are set.&lt;br /&gt;
; allowunknown : Skip implicit validation against the list of known file types.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filetypes&#039;, &#039;doctypes&#039;, get_string(&#039;doctypes&#039;, &#039;tool_myplugin&#039;), [&#039;onlytypes&#039; =&amp;gt; [&#039;document&#039;], &#039;allowunknown&#039; =&amp;gt; true]);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==addGroup==&lt;br /&gt;
A &#039;group&#039; in formslib is just a group of elements that will have a label and will be included on one line. &lt;br /&gt;
&lt;br /&gt;
For example typical code to include a submit and cancel button on the same line : &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$buttonarray=array();&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;submitbutton&#039;, get_string(&#039;savechanges&#039;));&lt;br /&gt;
$buttonarray[] =&amp;amp; $mform-&amp;gt;createElement(&#039;submit&#039;, &#039;cancel&#039;, get_string(&#039;cancel&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($buttonarray, &#039;buttonar&#039;, &#039;&#039;, array(&#039; &#039;), false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
You use the same arguments for createElement as you do for addElement. Any label for the element in the third argument is normally ignored (but not in the case of the submit buttons above where the third argument is not for a label but is the text for the button).&lt;br /&gt;
&lt;br /&gt;
Here&#039;s a bad example (don&#039;t do this for real, use the &#039;optional&#039; =&amp;gt; true option of the date element): putting a date_selector (which is itself a group of elements) and a checkbox on the same line, note that you can disable every element in the group using the group name &#039;availablefromgroup&#039; but it doesn&#039;t disable the controlling element the &#039;availablefromenabled&#039; checkbox:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$availablefromgroup=array();&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;date_selector&#039;, &#039;availablefrom&#039;, &#039;&#039;);&lt;br /&gt;
$availablefromgroup[] =&amp;amp; $mform-&amp;gt;createElement(&#039;checkbox&#039;, &#039;availablefromenabled&#039;, &#039;&#039;, get_string(&#039;enable&#039;));&lt;br /&gt;
$mform-&amp;gt;addGroup($availablefromgroup, &#039;availablefromgroup&#039;, get_string(&#039;availablefromdate&#039;, &#039;data&#039;), &#039;&amp;amp;nbsp;&#039;, false);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;availablefromgroup&#039;, &#039;availablefromenabled&#039;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* If you want to put a group inside another array so that you can repeat items, use createElement instead of addGroup:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
* By default, groups modify the names of elements inside them by appending a number. This is often unhelpful, for example if you want to use disabledIf on the element. To prevent this behaviour, set the last parameter to false when creating a group.:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$group = $mform-&amp;gt;createElement(&#039;group&#039;, &#039;groupname&#039;, get_string(&#039;label&#039;), $groupitems, null, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
==addRule==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;elementname&#039;, get_string(&#039;error&#039;), &#039;rule type&#039;, &#039;extraruledata&#039;, &#039;server&#039;(default), false, false);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
The first param(element) is an element name and second(message) is the error message that will be displayed to the user.&lt;br /&gt;
The third parameter(type) is the type of rule. The fourth param(format) is used for extra data needed with some rules such as minlength and regex. The fifth parameter(validation) validates input data on server or client side, if validation is done on client side then it will be checked on the server side as well.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
 * @param    string     $element       Form element name&lt;br /&gt;
 * @param    string     $message       Message to display for invalid data&lt;br /&gt;
 * @param    string     $type          Rule type, use getRegisteredRules() to get types&lt;br /&gt;
 * @param    string     $format        (optional)Required for extra rule data&lt;br /&gt;
 * @param    string     $validation    (optional)Where to perform validation: &amp;quot;server&amp;quot;, &amp;quot;client&amp;quot;&lt;br /&gt;
 * @param    boolean    $reset         Client-side validation: reset the form element to its original value if there is an error?&lt;br /&gt;
 * @param    boolean    $force         Force the rule to be applied, even if the target form element does not exist&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;Common Rule Types&#039;&#039;&#039;&lt;br /&gt;
* required &lt;br /&gt;
* maxlength&lt;br /&gt;
* minlength&lt;br /&gt;
* rangelength&lt;br /&gt;
* email&lt;br /&gt;
* regex&lt;br /&gt;
* lettersonly&lt;br /&gt;
* alphanumeric&lt;br /&gt;
* numeric&lt;br /&gt;
* nopunctuation&lt;br /&gt;
* nonzero&lt;br /&gt;
* callback&lt;br /&gt;
* compare&lt;br /&gt;
===Server side and Client side===&lt;br /&gt;
In case you use the &#039;&#039;Client side&#039;&#039; validation option, you can mainly check for an empty or not input field. unless you write some &#039;&#039;Client side&#039;&#039; code which will probably be JavaScript functions to verify the data inside the input fields before it is submitted to the server. It could save some time if those functions are short, simple and quick to compute.&lt;br /&gt;
In case you need a more complex validation checks which relay on Moodle&#039;s internal PHP libraries (or other/external PHP libraries) you better use the &#039;&#039;Server side&#039;&#039; validation checks. Where you can query the DB, write complex PHP validation functions and much much more, that are not available (easily) when using JavaScript on the client&#039;s side.&lt;br /&gt;
==addHelpButton==&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;api_key_field&#039;, &#039;api_key&#039;, &#039;block_extsearch&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
The following parameters are expected:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * @param $elementname The name of the form element to add the help button for&lt;br /&gt;
 * @param $identifier The identifier for the help string and its title (see below)&lt;br /&gt;
 * @param $component The component name to look for the help string in&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
# get_string($identifier, $component) // The title of the help page&lt;br /&gt;
# get_string(&amp;quot;{$identifier}_help&amp;quot;, $component) // The content of the help page&lt;br /&gt;
So you will need to have &#039;&#039;&#039;$identifier&#039;&#039;&#039; and &#039;&#039;&#039;{$identifier}_help&#039;&#039;&#039; defined in order for the help button to be created properly. For example the multiple choice question editing form has a button for shuffling the answers. &lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addHelpButton(&#039;shuffleanswers&#039;, &#039;shuffleanswers&#039;, &#039;qtype_multichoice&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
and so the language file includes the strings&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers&#039;] = &#039;Shuffle the choices?&#039;; &lt;br /&gt;
$string[&#039;shuffleanswers_help&#039;] = &#039;If enabled,.....&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
You can also add the language string like&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$string[&#039;shuffleanswers_link&#039;] = &#039;question/shuffleanswers&#039;;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
to add a link to more help on Moodle docs. See [[String_API]] for more information about help icons.&lt;br /&gt;
==setDefault==&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;select&#039;, &#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), $grades);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;grade&#039;, array(&#039;grade&#039;, get_string(&#039;gradeforsubmission&#039;, &#039;exercise&#039;), &#039;exercise&#039;));&lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;grade&#039;, 100);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Set the default of the form value with setDefault($elementname, $value); where elementname is the elementname whose default you want to set and $value is the default to set. We set the defaults for the form in definition(). This default is what is used if no data is loaded into the form with set_data(); eg. on display of the form for an &#039;add&#039; rather than &#039;update&#039; function.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;desc&#039;, get_string(&#039;description&#039;));     &lt;br /&gt;
$mform-&amp;gt;setDefault(&#039;desc&#039;, array(&#039;text&#039;=&amp;gt;$defaulttext));&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
Note that when setting the default for an editor element you must use an array to define the default &amp;quot;text&amp;quot; value as shown above.&lt;br /&gt;
==disabledIf==&lt;br /&gt;
For any element or groups of element in a form you can conditionally disable the group or individual element depending on conditions.&lt;br /&gt;
&lt;br /&gt;
You can use $mform-&amp;gt;disabledIf($elementName, $dependentOn, $condition = &#039;notchecked&#039;, $value=&#039;1&#039;)&lt;br /&gt;
* elementname can be a group. If you specify a group all elements in the group will be disabled (if dependentOn is in elementname group that is ignored and not disabled). These are the element names you&#039;ve used as the second argument in addElement or addGroup.&lt;br /&gt;
* dependentOn is the actual name of the element as it will appear in html. This can be different to the name used in addGroup particularly but also addElement where you&#039;re adding a complex element like a date_selector. Check the html of your page. You typically make the depedentOn a checkbox or select box.&lt;br /&gt;
* $condition will be &#039;notchecked&#039;, &#039;checked&#039;, &#039;noitemselected&#039;, &#039;eq&#039;, &#039;in&#039; or, if it is anything else, we test for &#039;neq&#039;.&lt;br /&gt;
** If $condition is &#039;eq&#039; or &#039;neq&#039; then we check the value of the dependentOn field and check for equality (==) or nonequality (!=) in js&lt;br /&gt;
** If $condition is &#039;checked&#039; or &#039;notchecked&#039; then we check to see if a checkbox is checked or not.&lt;br /&gt;
** If $condition is &#039;in&#039; then we check to see if a selected item is in the given list or not. (This was introduced in Moodle 2.7+)&lt;br /&gt;
** If $condition is &#039;noitemselected&#039; then we check to see whether nothing is selected in a dropdown list.&lt;br /&gt;
Examples:&lt;br /&gt;
 // Disable my control unless a checkbox is checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control if a checkbox &#039;&#039;&#039;is&#039;&#039;&#039; checked.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;somecheckbox&#039;, &#039;checked&#039;);&lt;br /&gt;
 &lt;br /&gt;
 // Disable my control when a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;eq&#039;, 42);&lt;br /&gt;
&lt;br /&gt;
 // Disable my control unless a dropdown has value 42.&lt;br /&gt;
 $mform-&amp;gt;disabledIf(&#039;mycontrol&#039;, &#039;someselect&#039;, &#039;neq&#039;, 42);&lt;br /&gt;
The possible choices here are in the dependency manager in lib/form/form.js.&lt;br /&gt;
===A tricky case===&lt;br /&gt;
You need to take care with disabledIf if you plan to use it with groups of checkboxes.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s say you have a group of 5 checkboxes and you want to enable a depending item such as a drop down menu only when the first and the last checkboxes are selected.&lt;br /&gt;
&lt;br /&gt;
To fix ideas:&lt;br /&gt;
&lt;br /&gt;
If the selection in the checkboxes group is:&lt;br /&gt;
 mycheck_01 == 1&lt;br /&gt;
 mycheck_02 == 0&lt;br /&gt;
 mycheck_03 == 0&lt;br /&gt;
 mycheck_04 == 0&lt;br /&gt;
 mycheck_05 == 1&lt;br /&gt;
the depending item must be enabled while ANY OTHER COMBINATION must disable the drop down menu.&lt;br /&gt;
&lt;br /&gt;
The following code will, apparently, fail:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;neq&#039;, &#039;0&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;neq&#039;, &#039;1&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
In fact, once you get the drop down menu enabled, you are free to unselect mycheck_01 whilst still having the depending item enabled.&lt;br /&gt;
This apparent bug occurs because a non-checked checkbox behaves like a non existing mform element. So the js code will not find the element &amp;quot;mycheck_01&amp;quot; and will not apply the corresponding rule.&lt;br /&gt;
&lt;br /&gt;
A working solution for this kind of issue seems to be:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_01&#039;, &#039;notchecked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_02&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_03&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_04&#039;, &#039;checked&#039;);&lt;br /&gt;
$mform-&amp;gt;disabledIf(&#039;dropdownmenu&#039;, &#039;mycheck_05&#039;, &#039;notchecked&#039;);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
To see a failing example as the one described, try the attachments provided in MDL-38975. See also in MDL-38975 for the working solution in action with modifications suggested by Eloy.&lt;br /&gt;
==hideIf==&lt;br /&gt;
{{Moodle 3.4}}&lt;br /&gt;
For any element or groups of element in a form you can conditionally hide the group or individual element depending on conditions.&lt;br /&gt;
This uses the same syntax as disabledIf just with hideIf instead.&lt;br /&gt;
==setType==&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned. These should be used for get parameters such as id, course etc. which are used to load a page and also with setType(); method. Every form element should have a type specified except select, radio box and checkbox elements, these elements do a good job of cleaning themselves (only specified options are allowed as user input).&lt;br /&gt;
===Most Commonly Used PARAM_* Types===&lt;br /&gt;
These are the most commonly used PARAM_* types and their proper uses. More types can be seen in moodlelib.php starting around line 100. For the full list, see the file lib/moodlelib.php.&lt;br /&gt;
* PARAM_CLEAN is deprecated and you should try to use a more specific type.&lt;br /&gt;
* PARAM_TEXT should be used for cleaning data that is expected to contain multi-lang content. It will strip all html tags. But will still let tags for multilang support through.&lt;br /&gt;
* PARAM_NOTAGS should be used for cleaning data that is expected to be plain text. It will strip *all* html type tags. It will *not* let tags for multilang support through. This should be used for instance for email addresses where no multilang support is appropriate.&lt;br /&gt;
* PARAM_RAW means no cleaning whatsoever, it is used mostly for data from the html editor. Data from the editor is later cleaned before display using format_text() function. PARAM_RAW can also be used for data that is validated by some other way or printed by p() or s().&lt;br /&gt;
* PARAM_INT should be used for integers. PARAM_FLOAT is also available for decimal numbers but is not recommended for user input since it does not work for languages that use , as a decimal separator.&lt;br /&gt;
&lt;br /&gt;
These types are deprecated:&lt;br /&gt;
* PARAM_CLEAN obsoleted, please use a more specific type of parameter. @deprecated since 2.0&lt;br /&gt;
* PARAM_ACTION deprecated alias for PARAM_ALPHA use for various actions in forms and urls. Use PARAM_ALPHANUMEXT instead.&lt;br /&gt;
&lt;br /&gt;
==disable_form_change_checker==&lt;br /&gt;
By default, any Moodle form will pop-up an &amp;quot;Are you sure?&amp;quot; alert if you make some changes and then try to leave the page without saving. Occasionally, that is undesirable, in which case you can call&lt;br /&gt;
 $mform-&amp;gt;disable_form_change_checker()&lt;br /&gt;
==References==&lt;br /&gt;
* [http://www.midnighthax.com/quickform.php PEAR HTML QuickForm Getting Started Guide] by Keith Edmunds of Midnighthax.com&lt;br /&gt;
* [http://pear.php.net/manual/en/package.html.html-quickform.php PEAR::HTML_QuickForm manual]&lt;br /&gt;
[[Category:Formslib]]&lt;br /&gt;
[[Category:Interfaces]]&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=63742</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=63742"/>
		<updated>2022-12-17T17:21:19Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Update script to include MOODLE_401_STABLE&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 MOODLE_{400..401}_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;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;$ git cherry-pick A^..B&amp;lt;/syntaxhighlight&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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=62204</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=62204"/>
		<updated>2022-05-03T09:54:02Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Update script to include MOODLE_400_STABLE&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 MOODLE_400_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;syntaxhighlight lang=&amp;quot;bash&amp;quot;&amp;gt;$ git cherry-pick A^..B&amp;lt;/syntaxhighlight&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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Assign_submission_plugins&amp;diff=61527</id>
		<title>Assign submission plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Assign_submission_plugins&amp;diff=61527"/>
		<updated>2021-11-19T15:46:27Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: 3.0.5/3.1.1 (MDL-41945) added assign_submission_plugin-&amp;gt;submission_is_empty()&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This page gives an overview of assignment submission plugims within the assignment module.&lt;br /&gt;
&lt;br /&gt;
=== Overview of an assignment submission plugin ===&lt;br /&gt;
An assignment submission plugin is used to display custom form fields to a student when they are editing their assignment submission. It also has full control over the display the submitted assignment to graders and students. Plugins participate in all assignment features including backup/restore, upgrades from 2.2, offline grading, group assignments and blind marking.&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
File:assignsubmission_plugin_overview1.png|An assignment submission plugin can add settings to the module settings page.&lt;br /&gt;
File:assignsubmission_plugin_overview2.png|An assignment submission plugin can show a summary of the submission to students and graders.&lt;br /&gt;
File:assignsubmission_plugin_overview3.png|An assignment submission plugin can add form fields to the student submission page.&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
Assignment submission plugins were added with the assignment module rewrite for Moodle 2.3. &lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
A great example is the &amp;quot;onlinetext&amp;quot; submission plugin included with Moodle core. &lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
The files for a custom submission plugin sit under &amp;quot;mod/assign/submission/&amp;lt;pluginname&amp;gt;&amp;quot;. A plugin should not include any custom files outside of it&#039;s own plugin folder. &lt;br /&gt;
&lt;br /&gt;
Note: The plugin name should be no longer than 11 characters - this is because the database tables for a submission plugin must be prefixed with &amp;quot;assignsubmission_&amp;quot; + pluginname (17 chars + X) and the table names can be no longer than 28 chars (thanks oracle). If a plugin requires multiple database tables, the plugin name will need to be shorter to allow different table names to fit under the 28 character limit.&lt;br /&gt;
&lt;br /&gt;
All examples in this document exclude the required copyright and license information from source files for brevity.&lt;br /&gt;
&lt;br /&gt;
=== version.php ===&lt;br /&gt;
&lt;br /&gt;
To start with we need to tell Moodle the version information for our new plugin so that it can be installed and upgraded correctly. This information is added to version.php as with any other type of Moodle plugin. The component name must begin with &amp;quot;assignsubmission_&amp;quot; to identify this as a submission plugin.&lt;br /&gt;
&lt;br /&gt;
See [[version.php]] for more information.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();                                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
$plugin-&amp;gt;version   = 2012112900;                                                                                                    &lt;br /&gt;
$plugin-&amp;gt;requires  = 2012112900;                                                                                                    &lt;br /&gt;
$plugin-&amp;gt;component = &#039;assignsubmission_file&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== settings.php ===&lt;br /&gt;
&lt;br /&gt;
The settings file allows us to add custom settings to the system wide configuration page for our plugin. &lt;br /&gt;
&lt;br /&gt;
All submission settings should be named &#039;assignsubmission_pluginname/settingname&#039; in order for the setting to be associated with the plugin.&lt;br /&gt;
&lt;br /&gt;
All submission plugins should include one setting named &#039;default&#039; to indicate if the plugin should be enabled by default when creating a new assignment. &lt;br /&gt;
&lt;br /&gt;
This example from the submission_file plugin also checks to see if there is a maxbytes setting for this moodle installation and if found, it adds a new admin setting to the settings page. The name of the setting should begin with the plugin component name (&amp;quot;assignsubmission_file&amp;quot;) in this case. The strings are specified in this plugins language file. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
// Note: This is on by default.                                                                                                     &lt;br /&gt;
$settings-&amp;gt;add(new admin_setting_configcheckbox(&#039;assignsubmission_file/default&#039;,                                                    &lt;br /&gt;
                   new lang_string(&#039;default&#039;, &#039;assignsubmission_file&#039;),                                                             &lt;br /&gt;
                   new lang_string(&#039;default_help&#039;, &#039;assignsubmission_file&#039;), 1));                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
if (isset($CFG-&amp;gt;maxbytes)) {                                                                                                        &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $name = new lang_string(&#039;maximumsubmissionsize&#039;, &#039;assignsubmission_file&#039;);                                                      &lt;br /&gt;
    $description = new lang_string(&#039;configmaxbytes&#039;, &#039;assignsubmission_file&#039;);                                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $element = new admin_setting_configselect(&#039;assignsubmission_file/maxbytes&#039;,                                                     &lt;br /&gt;
                                              $name,                                                                                &lt;br /&gt;
                                              $description,                                                                         &lt;br /&gt;
                                              1048576,                                                                              &lt;br /&gt;
                                              get_max_upload_sizes($CFG-&amp;gt;maxbytes));                                                &lt;br /&gt;
    $settings-&amp;gt;add($element);                                                                                                       &lt;br /&gt;
}                                                                          &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== lang/en/submission_pluginname.php ===&lt;br /&gt;
&lt;br /&gt;
The language file for this plugin must have the same name as the component name (e.g. &amp;quot;submission_file.php&amp;quot;). It should at least define a string for &amp;quot;pluginname&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Awesome submissions&#039;;      &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/access.php ===&lt;br /&gt;
&lt;br /&gt;
This is where any additional capabilities are defined if required. This file can be omitted if there are no capabilities added by the plugin.&lt;br /&gt;
&lt;br /&gt;
See [[Activity_modules#access.php]] for more information.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;assignsubmission/dungeon:master&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039; =&amp;gt; RISK_XSS,&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_COURSE,&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;
        &#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/course:manageactivities&#039;&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/upgrade.php ===&lt;br /&gt;
&lt;br /&gt;
This is where any upgrade code is defined. &lt;br /&gt;
&lt;br /&gt;
See [[Activity_modules#upgrade.php]] for more infomation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function xmldb_submission_file_upgrade($oldversion) {&lt;br /&gt;
    global $CFG, $DB, $OUTPUT;&lt;br /&gt;
&lt;br /&gt;
    $dbman = $DB-&amp;gt;get_manager();&lt;br /&gt;
    if ($oldversion &amp;lt; 2012091800) {&lt;br /&gt;
        // Put upgrade code here&lt;br /&gt;
&lt;br /&gt;
        // Savepoint reached.&lt;br /&gt;
        upgrade_plugin_savepoint(true, 2012091800, &#039;assignsubmission&#039;, &#039;file&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/install.xml ===&lt;br /&gt;
&lt;br /&gt;
This is where any database tables required to save this plugins data are defined. File submissions define a table that links to submission and contains a column to record the number of files. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; ?&amp;gt;                                                                                             &lt;br /&gt;
&amp;lt;XMLDB PATH=&amp;quot;mod/assign/submission/file/db&amp;quot; VERSION=&amp;quot;20120423&amp;quot; COMMENT=&amp;quot;XMLDB file for Moodle mod/assign/submission/file&amp;quot;           &lt;br /&gt;
    xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;                                                                           &lt;br /&gt;
    xsi:noNamespaceSchemaLocation=&amp;quot;../../../../../lib/xmldb/xmldb.xsd&amp;quot;                                                              &lt;br /&gt;
&amp;gt;                                                                                                                                   &lt;br /&gt;
  &amp;lt;TABLES&amp;gt;                                                                                                                          &lt;br /&gt;
    &amp;lt;TABLE NAME=&amp;quot;assignsubmission_file&amp;quot; COMMENT=&amp;quot;Info about file submissions for assignments&amp;quot;&amp;gt;                                      &lt;br /&gt;
      &amp;lt;FIELDS&amp;gt;                                                                                                                      &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;id&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; SEQUENCE=&amp;quot;true&amp;quot;/&amp;gt;                                                    &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;assignment&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; DEFAULT=&amp;quot;0&amp;quot; SEQUENCE=&amp;quot;false&amp;quot;/&amp;gt;                               &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;submission&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; DEFAULT=&amp;quot;0&amp;quot; SEQUENCE=&amp;quot;false&amp;quot;/&amp;gt;                               &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;numfiles&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; DEFAULT=&amp;quot;0&amp;quot; SEQUENCE=&amp;quot;false&amp;quot; COMMENT=&amp;quot;The number of files the student submitted.&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/FIELDS&amp;gt;                                                                                                                     &lt;br /&gt;
      &amp;lt;KEYS&amp;gt;                                                                                                                        &lt;br /&gt;
        &amp;lt;KEY NAME=&amp;quot;primary&amp;quot; TYPE=&amp;quot;primary&amp;quot; FIELDS=&amp;quot;id&amp;quot; COMMENT=&amp;quot;The unique id for this submission info.&amp;quot;/&amp;gt;                          &lt;br /&gt;
        &amp;lt;KEY NAME=&amp;quot;assignment&amp;quot; TYPE=&amp;quot;foreign&amp;quot; FIELDS=&amp;quot;assignment&amp;quot; REFTABLE=&amp;quot;assign&amp;quot; REFFIELDS=&amp;quot;id&amp;quot; COMMENT=&amp;quot;The assignment instance this submission relates to&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;KEY NAME=&amp;quot;submission&amp;quot; TYPE=&amp;quot;foreign&amp;quot; FIELDS=&amp;quot;submission&amp;quot; REFTABLE=&amp;quot;assign_submission&amp;quot; REFFIELDS=&amp;quot;id&amp;quot; COMMENT=&amp;quot;The submission this file submission relates to.&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/KEYS&amp;gt;                                                                                                                       &lt;br /&gt;
    &amp;lt;/TABLE&amp;gt;                                                                                                                        &lt;br /&gt;
  &amp;lt;/TABLES&amp;gt;                                                                                                                         &lt;br /&gt;
&amp;lt;/XMLDB&amp;gt;                           &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/install.php ===&lt;br /&gt;
&lt;br /&gt;
This example is from the submission_comments plugin. It shows how to run custom code on installation of the plugin. In this case it makes the comments plugin the last of the three submission plugins installed by default. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Code run after the plugin database tables have been created.&lt;br /&gt;
 */&lt;br /&gt;
function xmldb_assignsubmission_comments_install() {&lt;br /&gt;
    global $CFG, $DB, $OUTPUT;&lt;br /&gt;
&lt;br /&gt;
    // do the install&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
    // set the correct initial order for the plugins&lt;br /&gt;
    $assignment = new assignment();&lt;br /&gt;
    $plugin = $assignment-&amp;gt;get_submission_plugin_by_type(&#039;comments&#039;);&lt;br /&gt;
    if ($plugin) {&lt;br /&gt;
        $plugin-&amp;gt;move(&#039;down&#039;);&lt;br /&gt;
        $plugin-&amp;gt;move(&#039;down&#039;);&lt;br /&gt;
    }&lt;br /&gt;
        &lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== locallib.php ===&lt;br /&gt;
&lt;br /&gt;
This is where all the functionality for this plugin is defined. We will step through this file and describe each part as we go.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class assign_submission_file extends assign_submission_plugin {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All submission plugins MUST define a class with the component name of the plugin that extends assign_submission_plugin. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_name()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    public function get_name() {&lt;br /&gt;
        return get_string(&#039;file&#039;, &#039;assignsubmission_file&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Get name is abstract in submission_plugin and must be defined in your new plugin. Use the language strings to make your plugin translatable. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_settings()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_settings(MoodleQuickForm $mform) {&lt;br /&gt;
       global $CFG, $COURSE;                                                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $defaultmaxfilesubmissions = $this-&amp;gt;get_config(&#039;maxfilesubmissions&#039;);                                                       &lt;br /&gt;
        $defaultmaxsubmissionsizebytes = $this-&amp;gt;get_config(&#039;maxsubmissionsizebytes&#039;);                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $settings = array();                                                                                                        &lt;br /&gt;
        $options = array();                                                                                                         &lt;br /&gt;
        for ($i = 1; $i &amp;lt;= ASSIGNSUBMISSION_FILE_MAXFILES; $i++) {                                                                  &lt;br /&gt;
            $options[$i] = $i;                                                                                                      &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $name = get_string(&#039;maxfilessubmission&#039;, &#039;assignsubmission_file&#039;);                                                          &lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;select&#039;, &#039;assignsubmission_file_maxfiles&#039;, $name, $options);                                            &lt;br /&gt;
        $mform-&amp;gt;addHelpButton(&#039;assignsubmission_file_maxfiles&#039;,                                                                     &lt;br /&gt;
                              &#039;maxfilessubmission&#039;,                                                                                 &lt;br /&gt;
                              &#039;assignsubmission_file&#039;);                                                                             &lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;assignsubmission_file_maxfiles&#039;, $defaultmaxfilesubmissions);                                           &lt;br /&gt;
        $mform-&amp;gt;disabledIf(&#039;assignsubmission_file_maxfiles&#039;, &#039;assignsubmission_file_enabled&#039;, &#039;notchecked&#039;);                        &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $choices = get_max_upload_sizes($CFG-&amp;gt;maxbytes,                                                                             &lt;br /&gt;
                                        $COURSE-&amp;gt;maxbytes,                                                                          &lt;br /&gt;
                                        get_config(&#039;assignsubmission_file&#039;, &#039;maxbytes&#039;));                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $settings[] = array(&#039;type&#039; =&amp;gt; &#039;select&#039;,                                                                                     &lt;br /&gt;
                            &#039;name&#039; =&amp;gt; &#039;maxsubmissionsizebytes&#039;,                                                                     &lt;br /&gt;
                            &#039;description&#039; =&amp;gt; get_string(&#039;maximumsubmissionsize&#039;, &#039;assignsubmission_file&#039;),                          &lt;br /&gt;
                            &#039;options&#039;=&amp;gt; $choices,                                                                                   &lt;br /&gt;
                            &#039;default&#039;=&amp;gt; $defaultmaxsubmissionsizebytes);                                                            &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $name = get_string(&#039;maximumsubmissionsize&#039;, &#039;assignsubmission_file&#039;);                                                       &lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;select&#039;, &#039;assignsubmission_file_maxsizebytes&#039;, $name, $choices);                                        &lt;br /&gt;
        $mform-&amp;gt;addHelpButton(&#039;assignsubmission_file_maxsizebytes&#039;,                                                                 &lt;br /&gt;
                              &#039;maximumsubmissionsize&#039;,                                                                              &lt;br /&gt;
                              &#039;assignsubmission_file&#039;);                                                                             &lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;assignsubmission_file_maxsizebytes&#039;, $defaultmaxsubmissionsizebytes);                                   &lt;br /&gt;
        $mform-&amp;gt;disabledIf(&#039;assignsubmission_file_maxsizebytes&#039;,                                                                    &lt;br /&gt;
                           &#039;assignsubmission_file_enabled&#039;,                                                                         &lt;br /&gt;
                           &#039;notchecked&#039;);                             &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;get_settings&amp;quot; function is called when building the settings page for the assignment. It allows this plugin to add a list of settings to the form. Notice that the settings are prefixed by the plugin name which is good practice to avoid conflicts with other plugins. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; save_settings()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function save_settings(stdClass $data) {                                                                                 &lt;br /&gt;
        $this-&amp;gt;set_config(&#039;maxfilesubmissions&#039;, $data-&amp;gt;assignsubmission_file_maxfiles);                                             &lt;br /&gt;
        $this-&amp;gt;set_config(&#039;maxsubmissionsizebytes&#039;, $data-&amp;gt;assignsubmission_file_maxsizebytes);                                     &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;save_settings&amp;quot; function is called when the assignment settings page is submitted, either for a new assignment or when editing an existing one. For settings specific to a single instance of the assignment you can use the assign_plugin::set_config function shown here to save key/value pairs against this assignment instance for this plugin. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_form_elements()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_form_elements($submission, MoodleQuickForm $mform, stdClass $data) {                                        &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        if ($this-&amp;gt;get_config(&#039;maxfilesubmissions&#039;) &amp;lt;= 0) {                                                                         &lt;br /&gt;
            return false;                                                                                                           &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $fileoptions = $this-&amp;gt;get_file_options();                                                                                   &lt;br /&gt;
        $submissionid = $submission ? $submission-&amp;gt;id : 0;                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $data = file_prepare_standard_filemanager($data,                                                                            &lt;br /&gt;
                                                  &#039;files&#039;,                                                                          &lt;br /&gt;
                                                  $fileoptions,                                                                     &lt;br /&gt;
                                                  $this-&amp;gt;assignment-&amp;gt;get_context(),                                                 &lt;br /&gt;
                                                  &#039;assignsubmission_file&#039;,                                                          &lt;br /&gt;
                                                  ASSIGNSUBMISSION_FILE_FILEAREA,                                                   &lt;br /&gt;
                                                  $submissionid);                                                                   &lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;files_filemanager&#039;, html_writer::tag(&#039;span&#039;, $this-&amp;gt;get_name(),                          &lt;br /&gt;
            array(&#039;class&#039; =&amp;gt; &#039;accesshide&#039;)), null, $fileoptions);                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }                                    &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The get_form_elements function is called when building the submission form. It functions identically to the get_settings function except that the submission object is available (if there is a submission) to associate the settings with a single submission. This example also shows how to use a filemanager within a submission plugin. The function must return true if it has modified the form otherwise the assignment will not include a header for this plugin. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; save()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   public function save(stdClass $submission, stdClass $data) {                                                                    &lt;br /&gt;
        global $USER, $DB;                                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $fileoptions = $this-&amp;gt;get_file_options();                                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $data = file_postupdate_standard_filemanager($data,                                                                         &lt;br /&gt;
                                                     &#039;files&#039;,                                                                       &lt;br /&gt;
                                                     $fileoptions,                                                                  &lt;br /&gt;
                                                     $this-&amp;gt;assignment-&amp;gt;get_context(),                                              &lt;br /&gt;
                                                     &#039;assignsubmission_file&#039;,                                                       &lt;br /&gt;
                                                     ASSIGNSUBMISSION_FILE_FILEAREA,                                                &lt;br /&gt;
                                                     $submission-&amp;gt;id);                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $filesubmission = $this-&amp;gt;get_file_submission($submission-&amp;gt;id);                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Plagiarism code event trigger when files are uploaded.                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $fs = get_file_storage();                                                                                                   &lt;br /&gt;
        $files = $fs-&amp;gt;get_area_files($this-&amp;gt;assignment-&amp;gt;get_context()-&amp;gt;id,                                                          &lt;br /&gt;
                                     &#039;assignsubmission_file&#039;,                                                                       &lt;br /&gt;
                                     ASSIGNSUBMISSION_FILE_FILEAREA,                                                                &lt;br /&gt;
                                     $submission-&amp;gt;id,                                                                               &lt;br /&gt;
                                     &#039;id&#039;,                                                                                          &lt;br /&gt;
                                     false);                                                                                        &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $count = $this-&amp;gt;count_files($submission-&amp;gt;id, ASSIGNSUBMISSION_FILE_FILEAREA);                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Send files to event system.                                                                                              &lt;br /&gt;
        // This lets Moodle know that an assessable file was uploaded (eg for plagiarism detection).                                &lt;br /&gt;
        $eventdata = new stdClass();                                                                                                &lt;br /&gt;
        $eventdata-&amp;gt;modulename = &#039;assign&#039;;                                                                                          &lt;br /&gt;
        $eventdata-&amp;gt;cmid = $this-&amp;gt;assignment-&amp;gt;get_course_module()-&amp;gt;id;                                                              &lt;br /&gt;
        $eventdata-&amp;gt;itemid = $submission-&amp;gt;id;                                                                                       &lt;br /&gt;
        $eventdata-&amp;gt;courseid = $this-&amp;gt;assignment-&amp;gt;get_course()-&amp;gt;id;                                                                 &lt;br /&gt;
        $eventdata-&amp;gt;userid = $USER-&amp;gt;id;                                                                                             &lt;br /&gt;
        if ($count &amp;gt; 1) {                                                                                                           &lt;br /&gt;
            $eventdata-&amp;gt;files = $files;                                                                                             &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        $eventdata-&amp;gt;file = $files;                                    &lt;br /&gt;
        $eventdata-&amp;gt;pathnamehashes = array_keys($files);                                                                            &lt;br /&gt;
        events_trigger(&#039;assessable_file_uploaded&#039;, $eventdata);                                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        if ($filesubmission) {                                                                                                      &lt;br /&gt;
            $filesubmission-&amp;gt;numfiles = $this-&amp;gt;count_files($submission-&amp;gt;id,                                                         &lt;br /&gt;
                                                           ASSIGNSUBMISSION_FILE_FILEAREA);                                         &lt;br /&gt;
            return $DB-&amp;gt;update_record(&#039;assignsubmission_file&#039;, $filesubmission);                                                    &lt;br /&gt;
        } else {                                                                                                                    &lt;br /&gt;
            $filesubmission = new stdClass();                                                                                       &lt;br /&gt;
            $filesubmission-&amp;gt;numfiles = $this-&amp;gt;count_files($submission-&amp;gt;id,                                                         &lt;br /&gt;
                                                           ASSIGNSUBMISSION_FILE_FILEAREA);                                         &lt;br /&gt;
            $filesubmission-&amp;gt;submission = $submission-&amp;gt;id;                                                                          &lt;br /&gt;
            $filesubmission-&amp;gt;assignment = $this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id;                                                    &lt;br /&gt;
            return $DB-&amp;gt;insert_record(&#039;assignsubmission_file&#039;, $filesubmission) &amp;gt; 0;                                                &lt;br /&gt;
        }                                &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;save&amp;quot; function is called to save a user submission. The parameters are the submission object and the data from the submission form. This example calls file_postupdate_standard_filemanager to copy the files from the draft file area to the filearea for this submission, it then uses the event api to trigger an assessable_file_uploaded event for the plagiarism api. It then records the number of files in the plugin specific &amp;quot;assignsubmission_file&amp;quot; table. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_files()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_files($submission) {&lt;br /&gt;
        $result = array();                                                                                                          &lt;br /&gt;
        $fs = get_file_storage();                                                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $files = $fs-&amp;gt;get_area_files($this-&amp;gt;assignment-&amp;gt;get_context()-&amp;gt;id,                                                          &lt;br /&gt;
                                     &#039;assignsubmission_file&#039;,                                                                       &lt;br /&gt;
                                     ASSIGNSUBMISSION_FILE_FILEAREA,                                                                &lt;br /&gt;
                                     $submission-&amp;gt;id,                                                                               &lt;br /&gt;
                                     &#039;timemodified&#039;,                                                                                &lt;br /&gt;
                                     false);                                                                                        &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        foreach ($files as $file) {                                                                                                 &lt;br /&gt;
            $result[$file-&amp;gt;get_filename()] = $file;                                                                                 &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        return $result;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If this submission plugin produces one or more files, it should implement &amp;quot;get_files&amp;quot; so that the portfolio API can export a list of all the files from all of the plugins for this assignment submission. This is also used by the offline grading feature in the assignment.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; view_summary()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function view_summary(stdClass $submission, &amp;amp; $showviewlink) {                                                           &lt;br /&gt;
        $count = $this-&amp;gt;count_files($submission-&amp;gt;id, ASSIGNSUBMISSION_FILE_FILEAREA);                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Show we show a link to view all files for this plugin?                                                                   &lt;br /&gt;
        $showviewlink = $count &amp;gt; ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES;                                                             &lt;br /&gt;
        if ($count &amp;lt;= ASSIGNSUBMISSION_FILE_MAXSUMMARYFILES) {                                                                      &lt;br /&gt;
            return $this-&amp;gt;assignment-&amp;gt;render_area_files(&#039;assignsubmission_file&#039;,                                                    &lt;br /&gt;
                                                        ASSIGNSUBMISSION_FILE_FILEAREA,                                             &lt;br /&gt;
                                                        $submission-&amp;gt;id);                                                           &lt;br /&gt;
        } else {                                                                                                                    &lt;br /&gt;
            return get_string(&#039;countfiles&#039;, &#039;assignsubmission_file&#039;, $count);                                                       &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view_summary function is called to display a summary of the submission to both markers and students. It counts the number of files submitted and if it is more that a set number, it only displays a count of how many files are in the submission - otherwise it uses a helper function to write the entire list of files. This is because we want to keep the summaries really short so they can be displayed in a table. There will be a link to view the full submission on the submission status page. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; view()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function view($submission) {&lt;br /&gt;
        return $this-&amp;gt;assignment-&amp;gt;render_area_files(&#039;assignsubmission_file&#039;,                                                        &lt;br /&gt;
                                                    ASSIGNSUBMISSION_FILE_FILEAREA,                                                 &lt;br /&gt;
                                                    $submission-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view function is called to display the entire submission to both markers and students. In this case it uses the helper function in the assignment class to write the list of files. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; can_upgrade()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function can_upgrade($type, $version) {&lt;br /&gt;
&lt;br /&gt;
        $uploadsingle_type =&#039;uploadsingle&#039;;&lt;br /&gt;
        $upload_type =&#039;upload&#039;;&lt;br /&gt;
&lt;br /&gt;
        if (($type == $uploadsingle_type || $type == $upload_type) &amp;amp;&amp;amp; $version &amp;gt;= 2011112900) {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
        return false;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The can_upgrade function is used to identify old &amp;quot;Assignment 2.2&amp;quot; subtypes that can be upgraded by this plugin. This plugin supports upgrades from the old &amp;quot;upload&amp;quot; and &amp;quot;uploadsingle&amp;quot; assignment subtypes. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; upgrade_settings()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    public function upgrade_settings(context $oldcontext, stdClass $oldassignment, &amp;amp; $log) {                                        &lt;br /&gt;
        global $DB;                                                                                                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        if ($oldassignment-&amp;gt;assignmenttype == &#039;uploadsingle&#039;) {                                                                     &lt;br /&gt;
            $this-&amp;gt;set_config(&#039;maxfilesubmissions&#039;, 1);                                                                             &lt;br /&gt;
            $this-&amp;gt;set_config(&#039;maxsubmissionsizebytes&#039;, $oldassignment-&amp;gt;maxbytes);                                                  &lt;br /&gt;
            return true;                                                                                                            &lt;br /&gt;
        } else if ($oldassignment-&amp;gt;assignmenttype == &#039;upload&#039;) {                                                                    &lt;br /&gt;
            $this-&amp;gt;set_config(&#039;maxfilesubmissions&#039;, $oldassignment-&amp;gt;var1);                                                          &lt;br /&gt;
            $this-&amp;gt;set_config(&#039;maxsubmissionsizebytes&#039;, $oldassignment-&amp;gt;maxbytes);                                                  &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
            // Advanced file upload uses a different setting to do the same thing.                                                  &lt;br /&gt;
            $DB-&amp;gt;set_field(&#039;assign&#039;,                                                                                                &lt;br /&gt;
                           &#039;submissiondrafts&#039;,                                                                                      &lt;br /&gt;
                           $oldassignment-&amp;gt;var4,                                                                                    &lt;br /&gt;
                           array(&#039;id&#039;=&amp;gt;$this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id));                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
            // Convert advanced file upload &amp;quot;hide description before due date&amp;quot; setting.                                             &lt;br /&gt;
            $alwaysshow = 0;                                                                                                        &lt;br /&gt;
            if (!$oldassignment-&amp;gt;var3) {                                                                                            &lt;br /&gt;
                $alwaysshow = 1;                                                                                                    &lt;br /&gt;
            }                                                                                                                       &lt;br /&gt;
            $DB-&amp;gt;set_field(&#039;assign&#039;,                                                                                                &lt;br /&gt;
                           &#039;alwaysshowdescription&#039;,                                                                                 &lt;br /&gt;
                           $alwaysshow,                                                                                             &lt;br /&gt;
                           array(&#039;id&#039;=&amp;gt;$this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id));                                                     &lt;br /&gt;
            return true;                                                                                                            &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
    }                     &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function is called once per assignment instance to upgrade the settings from the old assignment to the new mod_assign. In this case it sets the maxbytes, maxfiles and alwaysshowdescription configuration settings. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; upgrade()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    public function upgrade($oldcontext,$oldassignment, $oldsubmission, $submission, &amp;amp; $log) {&lt;br /&gt;
        global $DB;&lt;br /&gt;
&lt;br /&gt;
        $file_submission = new stdClass();&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        $file_submission-&amp;gt;numfiles = $oldsubmission-&amp;gt;numfiles;&lt;br /&gt;
        $file_submission-&amp;gt;submission = $submission-&amp;gt;id;&lt;br /&gt;
        $file_submission-&amp;gt;assignment = $this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id;&lt;br /&gt;
&lt;br /&gt;
        if (!$DB-&amp;gt;insert_record(&#039;assign_submission_file&#039;, $file_submission) &amp;gt; 0) {&lt;br /&gt;
            $log .= get_string(&#039;couldnotconvertsubmission&#039;, &#039;mod_assign&#039;, $submission-&amp;gt;userid);&lt;br /&gt;
            return false;&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        // now copy the area files&lt;br /&gt;
        $this-&amp;gt;assignment-&amp;gt;copy_area_files_for_upgrade($oldcontext-&amp;gt;id,&lt;br /&gt;
                                                        &#039;mod_assignment&#039;,&lt;br /&gt;
                                                        &#039;submission&#039;,&lt;br /&gt;
                                                        $oldsubmission-&amp;gt;id,&lt;br /&gt;
                                                        // New file area&lt;br /&gt;
                                                        $this-&amp;gt;assignment-&amp;gt;get_context()-&amp;gt;id,&lt;br /&gt;
                                                        &#039;mod_assign&#039;,&lt;br /&gt;
                                                        ASSIGN_FILEAREA_SUBMISSION_FILES,&lt;br /&gt;
                                                        $submission-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
        return true;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;upgrade&amp;quot; function upgrades a single submission from the old assignment type to the new one. In this case it involves copying all the files from the old filearea to the new one. There is a helper function available in the assignment class for this (Note: the copy will be fast as it is just adding rows to the files table). If this function returns false, the upgrade will be aborted and rolled back.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_editor_fields()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;    public function () {                                                                                           &lt;br /&gt;
        return array(&#039;onlinetext&#039; =&amp;gt; get_string(&#039;pluginname&#039;, &#039;assignsubmission_comments&#039;));                                        &lt;br /&gt;
    }       &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example is from assignsubmission_onlinetext.  If the plugin uses a text-editor it is ideal if the plugin implements &amp;quot;get_editor_fields&amp;quot;. This allows the portfolio to retrieve the text from the plugin when exporting the list of files for a submission. This is required because the text is stored in the plugin specific table that is only known to the plugin itself. If a plugin supports multiple text areas it can return the name of each of them here.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_editor_text()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_editor_text($name, $submissionid) {                                                                         &lt;br /&gt;
        if ($name == &#039;onlinetext&#039;) {                                                                                                &lt;br /&gt;
            $onlinetextsubmission = $this-&amp;gt;get_onlinetext_submission($submissionid);                                                &lt;br /&gt;
            if ($onlinetextsubmission) {                                                                                            &lt;br /&gt;
                return $onlinetextsubmission-&amp;gt;onlinetext;                                                                           &lt;br /&gt;
            }                                                                                                                       &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        return &#039;&#039;;                                                                                                                  &lt;br /&gt;
    }             &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example is from assignsubmission_onlinetext.  If the plugin uses a text-editor it is ideal if the plugin implements &amp;quot;get_editor_text&amp;quot;. This allows the portfolio to retrieve the text from the plugin when exporting the list of files for a submission. This is required because the text is stored in the plugin specific table that is only known to the plugin itself. The name is used to distinguish between multiple text areas in the one plugin. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_editor_format()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_editor_format($name, $submissionid) {&lt;br /&gt;
        if ($name == &#039;onlinetext&#039;) {&lt;br /&gt;
            $onlinetext_submission = $this-&amp;gt;get_onlinetext_submission($submissionid);&lt;br /&gt;
            if ($onlinetext_submission) {&lt;br /&gt;
                return $onlinetext_submission-&amp;gt;onlineformat;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return 0;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This example is from assignsubmission_onlinetext. For the same reason as the previous function, if the plugin uses a text editor, it is ideal if the plugin implements &amp;quot;get_editor_format&amp;quot;. This allows the portfolio to retrieve the text from the plugin when exporting the list of files for a submission. This is required because the text is stored in the plugin specific table that is only known to the plugin itself. The name is used to distinguish between multiple text areas in the one plugin.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; is_empty()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function is_empty(stdClass $submission) {                                                                                &lt;br /&gt;
        return $this-&amp;gt;count_files($submission-&amp;gt;id, ASSIGNSUBMISSION_FILE_FILEAREA) == 0;                                            &lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a plugin has no submission data to show - it can return true from the is_empty function. This prevents a table row being added to the submission summary for this plugin. It is also used to check if a student has tried to save an assignment with no data.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; submission_is_empty()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    global $USER;&lt;br /&gt;
    $fs = get_file_storage();&lt;br /&gt;
    // Get a count of all the draft files, excluding any directories.&lt;br /&gt;
    $files = $fs-&amp;gt;get_area_files(context_user::instance($USER-&amp;gt;id)-&amp;gt;id,&lt;br /&gt;
                                 &#039;user&#039;,&lt;br /&gt;
                                 &#039;draft&#039;,&lt;br /&gt;
                                 $data-&amp;gt;files_filemanager,&lt;br /&gt;
                                 &#039;id&#039;,&lt;br /&gt;
                                 false);&lt;br /&gt;
    return count($files) == 0;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Determine if a submission is empty. This is distinct from is_empty() in that it is intended to be used to determine if a submission made before saving is empty.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; get_file_areas()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   public function get_file_areas() {                                                                                              &lt;br /&gt;
        return array(ASSIGNSUBMISSION_FILE_FILEAREA=&amp;gt;$this-&amp;gt;get_name());                                                            &lt;br /&gt;
    }    &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A plugin should implement get_file_areas if it supports saving of any files to moodle - this allows the file areas to be browsed by the moodle file manager.&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; copy_submission()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function copy_submission(stdClass $sourcesubmission, stdClass $destsubmission) {                                         &lt;br /&gt;
        global $DB;                                                                                                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Copy the files across.                                                                                                   &lt;br /&gt;
        $contextid = $this-&amp;gt;assignment-&amp;gt;get_context()-&amp;gt;id;                                                                          &lt;br /&gt;
        $fs = get_file_storage();                                                                                                   &lt;br /&gt;
        $files = $fs-&amp;gt;get_area_files($contextid,                                                                                    &lt;br /&gt;
                                     &#039;assignsubmission_file&#039;,                                                                       &lt;br /&gt;
                                     ASSIGNSUBMISSION_FILE_FILEAREA,                                                                &lt;br /&gt;
                                     $sourcesubmission-&amp;gt;id,                                                                         &lt;br /&gt;
                                     &#039;id&#039;,                                                                                          &lt;br /&gt;
                                     false);                                                                                        &lt;br /&gt;
        foreach ($files as $file) {                                                                                                 &lt;br /&gt;
            $fieldupdates = array(&#039;itemid&#039; =&amp;gt; $destsubmission-&amp;gt;id);                                                                 &lt;br /&gt;
            $fs-&amp;gt;create_file_from_storedfile($fieldupdates, $file);                                                                 &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // Copy the assignsubmission_file record.                                                                                   &lt;br /&gt;
        if ($filesubmission = $this-&amp;gt;get_file_submission($sourcesubmission-&amp;gt;id)) {                                                  &lt;br /&gt;
            unset($filesubmission-&amp;gt;id);                                                                                             &lt;br /&gt;
            $filesubmission-&amp;gt;submission = $destsubmission-&amp;gt;id;                                                                      &lt;br /&gt;
            $DB-&amp;gt;insert_record(&#039;assignsubmission_file&#039;, $filesubmission);                                                           &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }                                 &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Since Moodle 2.5 - a students submission can be copied to create a new submission attempt. Plugins should implement this function if they store data associated with the submission (most plugins).&lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; format_for_log()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   public function (stdClass $submission) {                                                                          &lt;br /&gt;
        // format the info for each submission plugin add_to_log                                                                    &lt;br /&gt;
        $filecount = $this-&amp;gt;count_files($submission-&amp;gt;id, ASSIGNSUBMISSION_FILE_FILEAREA);                                           &lt;br /&gt;
        $fileloginfo = &#039;&#039;;                                                                                                          &lt;br /&gt;
        $fileloginfo .= &#039; the number of file(s) : &#039; . $filecount . &amp;quot; file(s).&amp;lt;br&amp;gt;&amp;quot;;                                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        return $fileloginfo;                                                                                                        &lt;br /&gt;
    }                      &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The format_for_log function lets a plugin produce a really short summary of a submission suitable for adding to a log message. &lt;br /&gt;
&lt;br /&gt;
==== &#039;&#039;&#039; delete_instance()&#039;&#039;&#039; ====&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function delete_instance() {                                                                                             &lt;br /&gt;
        global $DB;                                                                                                                 &lt;br /&gt;
        // will throw exception on failure                                                                                          &lt;br /&gt;
        $DB-&amp;gt;delete_records(&#039;assignsubmission_file&#039;, array(&#039;assignment&#039;=&amp;gt;$this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id));                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The delete_instance function is called when a plugin is deleted. Note only database records need to be cleaned up - files belonging to fileareas for this assignment will be automatically cleaned up.&lt;br /&gt;
&lt;br /&gt;
=== lib.php ===&lt;br /&gt;
&lt;br /&gt;
This file is the entry point to many standard Moodle APIs for plugins. An example is that in order for a plugin to allow users to download files contained within a filearea belonging to the plugin, they must implement the componentname_pluginfile function in order to perform their own security checks.&lt;br /&gt;
&lt;br /&gt;
See [[File_API]] for more information.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function assignfeedback_file_pluginfile($course,                                                                                    &lt;br /&gt;
                                        $cm,                                                                                        &lt;br /&gt;
                                        context $context,                                                                           &lt;br /&gt;
                                        $filearea,                                                                                  &lt;br /&gt;
                                        $args,                                                                                      &lt;br /&gt;
                                        $forcedownload) {                                                                           &lt;br /&gt;
    global $USER, $DB;                                                                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    if ($context-&amp;gt;contextlevel != CONTEXT_MODULE) {                                                                                 &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    require_login($course, false, $cm);                                                                                             &lt;br /&gt;
    $itemid = (int)array_shift($args);                                                                                              &lt;br /&gt;
    $record = $DB-&amp;gt;get_record(&#039;assign_grades&#039;, array(&#039;id&#039;=&amp;gt;$itemid), &#039;userid,assignment&#039;, MUST_EXIST);                              &lt;br /&gt;
    $userid = $record-&amp;gt;userid;                                                                                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    if (!$assign = $DB-&amp;gt;get_record(&#039;assign&#039;, array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance))) {                                                         &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    if ($assign-&amp;gt;id != $record-&amp;gt;assignment) {                                                                                       &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Check is users feedback or has grading permission.                                                                           &lt;br /&gt;
    if ($USER-&amp;gt;id != $userid and !has_capability(&#039;mod/assign:grade&#039;, $context)) {                                                   &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $relativepath = implode(&#039;/&#039;, $args);                                                                                            &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $fullpath = &amp;quot;/{$context-&amp;gt;id}/assignfeedback_file/$filearea/$itemid/$relativepath&amp;quot;;                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    if (!$file = $fs-&amp;gt;get_file_by_hash(sha1($fullpath)) or $file-&amp;gt;is_directory()) {                                                 &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
    // Download MUST be forced - security!                                                                                          &lt;br /&gt;
    send_stored_file($file, 0, 0, true);                                                                                            &lt;br /&gt;
}                                            &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Useful classes ==&lt;br /&gt;
A submission plugin has access to a number of useful classes in the assignment module. See the phpdocs (or the code) for more information on these classes.&lt;br /&gt;
&lt;br /&gt;
=== assign_plugin ===&lt;br /&gt;
This abstract class is the base class for all assignment plugins (feedback or submission plugins).&lt;br /&gt;
&lt;br /&gt;
It provides access to the assign class which represents the current assignment instance through &amp;quot;$this-&amp;gt;assignment&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== assign_submission_plugin ===&lt;br /&gt;
This is the base class all assignment submission plugins must extend. It contains a small number of additional function that only apply to submission plugins. &lt;br /&gt;
&lt;br /&gt;
=== assign ===&lt;br /&gt;
This is the main class for interacting with the assignment module. &lt;br /&gt;
&lt;br /&gt;
It contains public functions that are useful for listing users, loading and updating submissions, loading and updating grades, displaying users etc.&lt;br /&gt;
&lt;br /&gt;
== Other features ==&lt;br /&gt;
&lt;br /&gt;
=== Add calendar events ===&lt;br /&gt;
&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
&lt;br /&gt;
From Moodle 3.1 onwards, submission plugins can add events to the Moodle calendar without side effects. These will be hidden and deleted in line with the assignment module. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Add release date to calendar&lt;br /&gt;
        $calendarevent = new stdClass();&lt;br /&gt;
        $calendarevent-&amp;gt;name         = get_string(&#039;calendareventname&#039;, &#039;assignsubmission_something&#039;);&lt;br /&gt;
        $calendarevent-&amp;gt;description  = get_string(&#039;calendareventdesc&#039;, &#039;assignsubmission_something&#039;);&lt;br /&gt;
        $calendarevent-&amp;gt;courseid     = $courseid;&lt;br /&gt;
        $calendarevent-&amp;gt;groupid      = 0;&lt;br /&gt;
        $calendarevent-&amp;gt;userid       = $userid;&lt;br /&gt;
        $calendarevent-&amp;gt;modulename   = &#039;assign&#039;;&lt;br /&gt;
        $calendarevent-&amp;gt;instance     = $instanceid;&lt;br /&gt;
        $calendarevent-&amp;gt;eventtype    = &#039;something_release&#039;; // For activity module&#039;s events, this can be used to set the alternative text of the event icon. Set it to &#039;pluginname&#039; unless you have a better string.&lt;br /&gt;
        $calendarevent-&amp;gt;timestart    = $releasedate;&lt;br /&gt;
        $calendarevent-&amp;gt;visible      = true;&lt;br /&gt;
        $calendarevent-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
        calendar_event::create($calendarevent);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This code should be placed in the &amp;quot;save_settings()&amp;quot; method of your assign_submission_plugin class.&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Assign_feedback_plugins&amp;diff=61396</id>
		<title>Assign feedback plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Assign_feedback_plugins&amp;diff=61396"/>
		<updated>2021-09-24T16:20:07Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* locallib.php */ Correction to function name&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Introduction ==&lt;br /&gt;
This page gives an overview of assignment feedback plugins.&lt;br /&gt;
&lt;br /&gt;
=== Overview of an assignment feedback plugin ===&lt;br /&gt;
An assignment feedback plugin can do many things including providing feedback to students about a submission. The grading interface for the assignment module provides many hooks that allow plugins to add their own entries and participate in the grading workflow. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== History ==&lt;br /&gt;
Assignment feedback plugins were added with the assignment module rewrite for Moodle 2.3. &lt;br /&gt;
&lt;br /&gt;
== Template ==&lt;br /&gt;
A good example is the &amp;quot;file&amp;quot; feedback plugin included with core because it uses most of the features of feedback plugins. &lt;br /&gt;
&lt;br /&gt;
== File structure ==&lt;br /&gt;
The files for a custom feedback plugin sit under &amp;quot;mod/assign/feedback/&amp;lt;pluginname&amp;gt;&amp;quot;. A plugin should not include any custom files outside of it&#039;s own plugin folder.&lt;br /&gt;
Note: The plugin name should be no longer than 13 characters - this is because the database tables for a submission plugin must be prefixed with &amp;quot;assignfeedback_&amp;quot; + pluginname (15 chars + X) and the table names can be no longer than 28 chars (thanks oracle). If a plugin requires multiple database tables, the plugin name will need to be shorter to allow different table names to fit under the 28 character limit.&lt;br /&gt;
All examples in this document exclude the required copyright and license information from source files for brevity.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== version.php ===&lt;br /&gt;
&lt;br /&gt;
To start with we need to tell Moodle the version information for our new plugin so that it can be installed and upgraded correctly. This information is added to version.php as with any other type of Moodle plugin. The component name must begin with &amp;quot;assignfeedback_&amp;quot; to identify this as a feedback plugin.&lt;br /&gt;
&lt;br /&gt;
See [[version.php]] for more information.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();                                                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
$plugin-&amp;gt;version   = 2012112900;                                                                                                    &lt;br /&gt;
$plugin-&amp;gt;requires  = 2012112900;                                                                                                    &lt;br /&gt;
$plugin-&amp;gt;component = &#039;assignfeedback_file&#039;;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== settings.php ===&lt;br /&gt;
&lt;br /&gt;
The settings file allows us to add custom settings to the system wide configuration page for our plugin. &lt;br /&gt;
&lt;br /&gt;
All feedback settings should be named &#039;assignfeedback_pluginname/settingname&#039; in order for the setting to be associated with the plugin.&lt;br /&gt;
&lt;br /&gt;
All feedback plugins should include one setting named &#039;default&#039; to indicate if the plugin should be enabled by default when creating a new assignment. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$settings-&amp;gt;add(new admin_setting_configcheckbox(&#039;assignfeedback_file/default&#039;,                                                      &lt;br /&gt;
                   new lang_string(&#039;default&#039;, &#039;assignfeedback_file&#039;),                                                               &lt;br /&gt;
                   new lang_string(&#039;default_help&#039;, &#039;assignfeedback_file&#039;), 0));                                                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== lang/en/assignfeedback_pluginname.php ===&lt;br /&gt;
&lt;br /&gt;
The language file for this plugin must have the same name as the component name (e.g. &amp;quot;assignfeedback_file.php&amp;quot;). It should at least define strings for &amp;quot;pluginname&amp;quot;, &amp;quot;enabled&amp;quot; and &amp;quot;enabled_help&amp;quot;. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$string[&#039;pluginname&#039;] = &#039;Awesome feedback&#039;;&lt;br /&gt;
$string[&#039;enabled&#039;] = &#039;Awesome feedback&#039;;&lt;br /&gt;
$string[&#039;enabled_help&#039;] = &#039;If enabled, the teacher will be able to provide awesome feedback &#039;; &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/access.php ===&lt;br /&gt;
&lt;br /&gt;
This is where any additional capabilities are defined if required. This file can be omitted if there are no capabilities added by the plugin.&lt;br /&gt;
&lt;br /&gt;
See [[Activity_modules#access.php]] for more information.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;assignfeedback/dungeon:master&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039; =&amp;gt; RISK_XSS,&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_COURSE,&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;
        &#039;clonepermissionsfrom&#039; =&amp;gt; &#039;moodle/course:manageactivities&#039;&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/upgrade.php ===&lt;br /&gt;
&lt;br /&gt;
This is where any upgrade code is defined. &lt;br /&gt;
&lt;br /&gt;
See [[Activity_modules#upgrade.php]] for more infomation.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function xmldb_feedback_file_upgrade($oldversion) {&lt;br /&gt;
    global $CFG, $DB, $OUTPUT;&lt;br /&gt;
&lt;br /&gt;
    $dbman = $DB-&amp;gt;get_manager();&lt;br /&gt;
    if ($oldversion &amp;lt; 2012091800) {&lt;br /&gt;
        // Put upgrade code here&lt;br /&gt;
&lt;br /&gt;
        // Savepoint reached.&lt;br /&gt;
        upgrade_plugin_savepoint(true, 2012091800, &#039;assignfeedback&#039;, &#039;file&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return true;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/install.xml ===&lt;br /&gt;
&lt;br /&gt;
This is where any database tables required to save this plugins data are defined. File submissions define a table that links to submission and contains a column to record the number of files. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;UTF-8&amp;quot; ?&amp;gt;                                                                                             &lt;br /&gt;
&amp;lt;XMLDB PATH=&amp;quot;mod/assign/feedback/file/db&amp;quot; VERSION=&amp;quot;20120423&amp;quot; COMMENT=&amp;quot;XMLDB file for Moodle mod/assign/feedback/file&amp;quot;               &lt;br /&gt;
    xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;                                                                           &lt;br /&gt;
    xsi:noNamespaceSchemaLocation=&amp;quot;../../../../../lib/xmldb/xmldb.xsd&amp;quot;                                                              &lt;br /&gt;
&amp;gt;                                                                                                                                   &lt;br /&gt;
  &amp;lt;TABLES&amp;gt;                                                                                                                          &lt;br /&gt;
    &amp;lt;TABLE NAME=&amp;quot;assignfeedback_file&amp;quot; COMMENT=&amp;quot;Stores info about the number of files submitted by a grader.&amp;quot;&amp;gt;                      &lt;br /&gt;
      &amp;lt;FIELDS&amp;gt;                                                                                                                      &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;id&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; SEQUENCE=&amp;quot;true&amp;quot;/&amp;gt;                                                    &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;assignment&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; DEFAULT=&amp;quot;0&amp;quot; SEQUENCE=&amp;quot;false&amp;quot;/&amp;gt;                               &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;grade&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; DEFAULT=&amp;quot;0&amp;quot; SEQUENCE=&amp;quot;false&amp;quot;/&amp;gt;                                    &lt;br /&gt;
        &amp;lt;FIELD NAME=&amp;quot;numfiles&amp;quot; TYPE=&amp;quot;int&amp;quot; LENGTH=&amp;quot;10&amp;quot; NOTNULL=&amp;quot;true&amp;quot; DEFAULT=&amp;quot;0&amp;quot; SEQUENCE=&amp;quot;false&amp;quot; COMMENT=&amp;quot;The number of files uploaded by a grader.&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/FIELDS&amp;gt;                                                                                                                     &lt;br /&gt;
      &amp;lt;KEYS&amp;gt;                                                                                                                        &lt;br /&gt;
        &amp;lt;KEY NAME=&amp;quot;primary&amp;quot; TYPE=&amp;quot;primary&amp;quot; FIELDS=&amp;quot;id&amp;quot; COMMENT=&amp;quot;Unique id for this feedback value.&amp;quot;/&amp;gt;                               &lt;br /&gt;
        &amp;lt;KEY NAME=&amp;quot;assignment&amp;quot; TYPE=&amp;quot;foreign&amp;quot; FIELDS=&amp;quot;assignment&amp;quot; REFTABLE=&amp;quot;assign&amp;quot; REFFIELDS=&amp;quot;id&amp;quot; COMMENT=&amp;quot;The assignment instance this feedback relates to.&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;KEY NAME=&amp;quot;grade&amp;quot; TYPE=&amp;quot;foreign&amp;quot; FIELDS=&amp;quot;grade&amp;quot; REFTABLE=&amp;quot;assign_grades&amp;quot; REFFIELDS=&amp;quot;id&amp;quot; COMMENT=&amp;quot;The grade instance this feedback relates to.&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/KEYS&amp;gt;                                                                                                                       &lt;br /&gt;
    &amp;lt;/TABLE&amp;gt;                                                                                                                        &lt;br /&gt;
  &amp;lt;/TABLES&amp;gt;                                                                                                                         &lt;br /&gt;
&amp;lt;/XMLDB&amp;gt;                                                 &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== db/install.php ===&lt;br /&gt;
&lt;br /&gt;
This file contains custom code to run on installation of the plugin. In this case it makes the files plugin the second of the feedback plugins installed by default. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
                                                                                                                           &lt;br /&gt;
function xmldb_assignfeedback_file_install() {                                                                                      &lt;br /&gt;
    global $CFG;                                                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/adminlib.php&#039;);                                                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Set the correct initial order for the plugins.                                                                               &lt;br /&gt;
    $pluginmanager = new assign_plugin_manager(&#039;assignfeedback&#039;);                                                                   &lt;br /&gt;
    $pluginmanager-&amp;gt;move_plugin(&#039;file&#039;, &#039;down&#039;);                                                                                    &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    return true;                                                                                                                    &lt;br /&gt;
}                      &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== lib.php ===&lt;br /&gt;
&lt;br /&gt;
This file is the entry point to many standard Moodle APIs for plugins. An example is that in order for a plugin to allow users to download files contained within a filearea belonging to the plugin, they must implement the componentname_pluginfile function in order to perform their own security checks.&lt;br /&gt;
&lt;br /&gt;
See [[File_API]] for more information.&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function assignfeedback_file_pluginfile($course,                                                                                    &lt;br /&gt;
                                        $cm,                                                                                        &lt;br /&gt;
                                        context $context,                                                                           &lt;br /&gt;
                                        $filearea,                                                                                  &lt;br /&gt;
                                        $args,                                                                                      &lt;br /&gt;
                                        $forcedownload) {                                                                           &lt;br /&gt;
    global $USER, $DB;                                                                                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    if ($context-&amp;gt;contextlevel != CONTEXT_MODULE) {                                                                                 &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    require_login($course, false, $cm);                                                                                             &lt;br /&gt;
    $itemid = (int)array_shift($args);                                                                                              &lt;br /&gt;
    $record = $DB-&amp;gt;get_record(&#039;assign_grades&#039;, array(&#039;id&#039;=&amp;gt;$itemid), &#039;userid,assignment&#039;, MUST_EXIST);                              &lt;br /&gt;
    $userid = $record-&amp;gt;userid;                                                                                                      &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    if (!$assign = $DB-&amp;gt;get_record(&#039;assign&#039;, array(&#039;id&#039;=&amp;gt;$cm-&amp;gt;instance))) {                                                         &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    if ($assign-&amp;gt;id != $record-&amp;gt;assignment) {                                                                                       &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    // Check is users feedback or has grading permission.                                                                           &lt;br /&gt;
    if ($USER-&amp;gt;id != $userid and !has_capability(&#039;mod/assign:grade&#039;, $context)) {                                                   &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $relativepath = implode(&#039;/&#039;, $args);                                                                                            &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $fullpath = &amp;quot;/{$context-&amp;gt;id}/assignfeedback_file/$filearea/$itemid/$relativepath&amp;quot;;                                              &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    $fs = get_file_storage();                                                                                                       &lt;br /&gt;
    if (!$file = $fs-&amp;gt;get_file_by_hash(sha1($fullpath)) or $file-&amp;gt;is_directory()) {                                                 &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
    // Download MUST be forced - security!                                                                                          &lt;br /&gt;
    send_stored_file($file, 0, 0, true);                                                                                            &lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== locallib.php ===&lt;br /&gt;
&lt;br /&gt;
This is where all the functionality for this plugin is defined. We will step through this file and describe each part as we go.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
class assign_feedback_file extends assign_feedback_plugin {&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
All feedback plugins MUST define a class with the component name of the plugin that extends assign_feedback_plugin. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    public function get_name() {&lt;br /&gt;
        return get_string(&#039;file&#039;, &#039;assignfeedback_file&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Get name is abstract in feedback_plugin and must be defined in your new plugin. Use the language strings to make your plugin translatable. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_settings(MoodleQuickForm $mform) {&lt;br /&gt;
         $mform-&amp;gt;addElement(&#039;assignfeedback_file_fileextensions&#039;, get_string(&#039;allowedfileextensions&#039;, &#039;assignfeedback_file&#039;));&lt;br /&gt;
         $mform-&amp;gt;setType(&#039;assignfeedback_file_fileextensions&#039;, PARAM_FILE);&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;get_settings&amp;quot; function is called when building the settings page for the assignment. It allows this plugin to add a list of settings to the form. Notice that the settings should be prefixed by the plugin name which is good practice to avoid conflicts with other plugins. (None of the core feedback plugins have any instance settings, so this example is fictional).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function save_settings(stdClass $data) {                                                                                 &lt;br /&gt;
        $this-&amp;gt;set_config(&#039;allowedfileextensions&#039;, $data-&amp;gt;allowedfileextensions);                                             &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;save_settings&amp;quot; function is called when the assignment settings page is submitted, either for a new assignment or when editing an existing one. For settings specific to a single instance of the assignment you can use the assign_plugin::set_config function shown here to save key/value pairs against this assignment instance for this plugin. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_form_elements_for_user($grade, MoodleQuickForm $mform, stdClass $data, $userid)                                       &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $fileoptions = $this-&amp;gt;get_file_options();                                                                                   &lt;br /&gt;
        $gradeid = $grade ? $grade-&amp;gt;id : 0;                                                                                         &lt;br /&gt;
        $elementname = &#039;files_&#039; . $userid;                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $data = file_prepare_standard_filemanager($data,                                                                            &lt;br /&gt;
                                                  $elementname,                                                                     &lt;br /&gt;
                                                  $fileoptions,                                                                     &lt;br /&gt;
                                                  $this-&amp;gt;assignment-&amp;gt;get_context(),                                                 &lt;br /&gt;
                                                  &#039;assignfeedback_file&#039;,                                                            &lt;br /&gt;
                                                  ASSIGNFEEDBACK_FILE_FILEAREA,                                                     &lt;br /&gt;
                                                  $gradeid);                                                                        &lt;br /&gt;
        $mform-&amp;gt;addElement(&#039;filemanager&#039;, $elementname . &#039;_filemanager&#039;, html_writer::tag(&#039;span&#039;, $this-&amp;gt;get_name(),                &lt;br /&gt;
            array(&#039;class&#039; =&amp;gt; &#039;accesshide&#039;)), null, $fileoptions);                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }                                              &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;get_form_elements_for_user&amp;quot; function is called when building the feedback form. It functions identically to the get_settings function except that the grade object is available (if there is a grade) to associate the settings with a single grade attempt. This example also shows how to use a filemanager within a feedback plugin. The function must return true if it has modified the form otherwise the assignment will not include a header for this plugin. Notice there is an older version of this function &amp;quot;get_form_elements&amp;quot; which does not accept a userid as a parameter - this version is less useful - not recommended. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function is_feedback_modified(stdClass $grade, stdClass $data) {&lt;br /&gt;
        $commenttext = &#039;&#039;;&lt;br /&gt;
        if ($grade) {&lt;br /&gt;
            $feedbackcomments = $this-&amp;gt;get_feedback_comments($grade-&amp;gt;id);&lt;br /&gt;
            if ($feedbackcomments) {&lt;br /&gt;
                $commenttext = $feedbackcomments-&amp;gt;commenttext;&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        if ($commenttext == $data-&amp;gt;assignfeedbackcomments_editor[&#039;text&#039;]) {&lt;br /&gt;
            return false;&lt;br /&gt;
        } else {&lt;br /&gt;
            return true;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The is_feedback_modified function is called before feedback is saved. If feedback has not been modified then the save() method is not called. This function takes the grade object and submitted data from the grading form. In this example we are comparing the existing text comments made with the new ones. This function must return a boolean; True if the feedback has been modified; False if there has been no modification made. If this method is not overwritten then it will default to returning True.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   public function save(stdClass $grade, stdClass $data) {                                                                         &lt;br /&gt;
        global $DB;                                                                                                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $fileoptions = $this-&amp;gt;get_file_options();                                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $userid = $grade-&amp;gt;userid;                                                                                                   &lt;br /&gt;
        $elementname = &#039;files_&#039; . $userid;                                                                                          &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $data = file_postupdate_standard_filemanager($data,                                                                         &lt;br /&gt;
                                                     $elementname,                                                                  &lt;br /&gt;
                                                     $fileoptions,                                                                  &lt;br /&gt;
                                                     $this-&amp;gt;assignment-&amp;gt;get_context(),                                              &lt;br /&gt;
                                                     &#039;assignfeedback_file&#039;,                                                         &lt;br /&gt;
                                                     ASSIGNFEEDBACK_FILE_FILEAREA,                                                  &lt;br /&gt;
                                                     $grade-&amp;gt;id);                                                                   &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        $filefeedback = $this-&amp;gt;get_file_feedback($grade-&amp;gt;id);                                                                       &lt;br /&gt;
        if ($filefeedback) {                                                                                                        &lt;br /&gt;
            $filefeedback-&amp;gt;numfiles = $this-&amp;gt;count_files($grade-&amp;gt;id, ASSIGNFEEDBACK_FILE_FILEAREA);                                 &lt;br /&gt;
            return $DB-&amp;gt;update_record(&#039;assignfeedback_file&#039;, $filefeedback);                                                        &lt;br /&gt;
        } else {                                                                                                                    &lt;br /&gt;
            $filefeedback = new stdClass();                                                                                         &lt;br /&gt;
            $filefeedback-&amp;gt;numfiles = $this-&amp;gt;count_files($grade-&amp;gt;id, ASSIGNFEEDBACK_FILE_FILEAREA);                                 &lt;br /&gt;
            $filefeedback-&amp;gt;grade = $grade-&amp;gt;id;                                                                                      &lt;br /&gt;
            $filefeedback-&amp;gt;assignment = $this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id;                                                      &lt;br /&gt;
            return $DB-&amp;gt;insert_record(&#039;assignfeedback_file&#039;, $filefeedback) &amp;gt; 0;                                                    &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
    }                                         &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;save&amp;quot; function is called to save a graders feedback. The parameters are the grade object and the data from the feedback form. This example calls file_postupdate_standard_filemanager to copy the files from the draft file area to the filearea for this feedback. It then records the number of files in the plugin specific &amp;quot;assignfeedback_file&amp;quot; table. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function view_summary(stdClass $grade, &amp;amp; $showviewlink) {                                                                &lt;br /&gt;
        $count = $this-&amp;gt;count_files($grade-&amp;gt;id, ASSIGNFEEDBACK_FILE_FILEAREA);                                                      &lt;br /&gt;
        // show a view all link if the number of files is over this limit                                                           &lt;br /&gt;
        $showviewlink = $count &amp;gt; ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES;                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        if ($count &amp;lt;= ASSIGNFEEDBACK_FILE_MAXSUMMARYFILES) {                                                                        &lt;br /&gt;
            return $this-&amp;gt;assignment-&amp;gt;render_area_files(&#039;assignfeedback_file&#039;, ASSIGNFEEDBACK_FILE_FILEAREA, $grade-&amp;gt;id);           &lt;br /&gt;
        } else {                                                                                                                    &lt;br /&gt;
            return get_string(&#039;countfiles&#039;, &#039;assignfeedback_file&#039;, $count);                                                         &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
    }                          &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view_summary function is called to display a summary of the feedback to both markers and students. It counts the number of files and if it is more that a set number, it only displays a count of how many files are in the feedback - otherwise it uses a helper function to write the entire list of files. This is because we want to keep the summaries really short so they can be displayed in a table. There will be a link to view the full feedback on the submission status page. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function view(stdClass $grade) {                                                                                         &lt;br /&gt;
        return $this-&amp;gt;assignment-&amp;gt;render_area_files(&#039;assignfeedback_file&#039;, ASSIGNFEEDBACK_FILE_FILEAREA, $grade-&amp;gt;id);               &lt;br /&gt;
    }    &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The view function is called to display the entire feedback to both markers and students. In this case it uses the helper function in the assignment class to write the list of files. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function can_upgrade($type, $version) {                                                                                  &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        if (($type == &#039;upload&#039; || $type == &#039;uploadsingle&#039;) &amp;amp;&amp;amp; $version &amp;gt;= 2011112900) {                                             &lt;br /&gt;
            return true;                                                                                                            &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }       &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The can_upgrade function is used to identify old &amp;quot;Assignment 2.2&amp;quot; subtypes that can be upgraded by this plugin. This plugin supports upgrades from the old &amp;quot;upload&amp;quot; and &amp;quot;uploadsingle&amp;quot; assignment subtypes. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    &lt;br /&gt;
    public function upgrade_settings(context $oldcontext, stdClass $oldassignment, &amp;amp; $log) {                                        &lt;br /&gt;
        // first upgrade settings (nothing to do)                                                                                   &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }                  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This function is called once per assignment instance to upgrade the settings from the old assignment to the new mod_assign. In this case it returns true as there are no settings to upgrade. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
    public function upgrade(context $oldcontext, stdClass $oldassignment, stdClass $oldsubmission, stdClass $grade, &amp;amp; $log) {       &lt;br /&gt;
        global $DB;                                                                                                                 &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // now copy the area files                                                                                                  &lt;br /&gt;
        $this-&amp;gt;assignment-&amp;gt;copy_area_files_for_upgrade($oldcontext-&amp;gt;id,                                                             &lt;br /&gt;
                                                        &#039;mod_assignment&#039;,                                                           &lt;br /&gt;
                                                        &#039;response&#039;,                                                                 &lt;br /&gt;
                                                        $oldsubmission-&amp;gt;id,                                                         &lt;br /&gt;
                                                        // New file area                                                            &lt;br /&gt;
                                                        $this-&amp;gt;assignment-&amp;gt;get_context()-&amp;gt;id,                                       &lt;br /&gt;
                                                        &#039;assignfeedback_file&#039;,                                                      &lt;br /&gt;
                                                        ASSIGNFEEDBACK_FILE_FILEAREA,                                               &lt;br /&gt;
                                                        $grade-&amp;gt;id);                                                                &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        // now count them!                                                                                                          &lt;br /&gt;
        $filefeedback = new stdClass();                                                                                             &lt;br /&gt;
        $filefeedback-&amp;gt;numfiles = $this-&amp;gt;count_files($grade-&amp;gt;id, ASSIGNFEEDBACK_FILE_FILEAREA);                                     &lt;br /&gt;
        $filefeedback-&amp;gt;grade = $grade-&amp;gt;id;                                                                                          &lt;br /&gt;
        $filefeedback-&amp;gt;assignment = $this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id;                                                          &lt;br /&gt;
        if (!$DB-&amp;gt;insert_record(&#039;assignfeedback_file&#039;, $filefeedback) &amp;gt; 0) {                                                        &lt;br /&gt;
            $log .= get_string(&#039;couldnotconvertgrade&#039;, &#039;mod_assign&#039;, $grade-&amp;gt;userid);                                               &lt;br /&gt;
            return false;                                                                                                           &lt;br /&gt;
        }                                                                                                                           &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }                &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;upgrade&amp;quot; function upgrades a single submission from the old assignment type to the new one. In this case it involves copying all the files from the old filearea to the new one. There is a helper function available in the assignment class for this (Note: the copy will be fast as it is just adding rows to the files table). If this function returns false, the upgrade will be aborted and rolled back.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function is_empty(stdClass $submission) {                                                                                &lt;br /&gt;
        return $this-&amp;gt;count_files($submission-&amp;gt;id, ASSIGNSUBMISSION_FILE_FILEAREA) == 0;                                            &lt;br /&gt;
    }   &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If a plugin has no data to show - it can return true from the is_empty function. This prevents a table row being added to the feedback summary for this plugin. It is also used to check if a grader has tried to save feedback with no data.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function get_file_areas() {                                                                                              &lt;br /&gt;
        return array(ASSIGNFEEDBACK_FILE_FILEAREA=&amp;gt;$this-&amp;gt;get_name());                                                              &lt;br /&gt;
    }      &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
A plugin should implement get_file_areas if it supports saving of any files to moodle - this allows the file areas to be browsed by the moodle file manager.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function delete_instance() {                                                                                             &lt;br /&gt;
        global $DB;                                                                                                                 &lt;br /&gt;
        // will throw exception on failure                                                                                          &lt;br /&gt;
        $DB-&amp;gt;delete_records(&#039;assignfeedback_file&#039;, array(&#039;assignment&#039;=&amp;gt;$this-&amp;gt;assignment-&amp;gt;get_instance()-&amp;gt;id));                     &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
        return true;                                                                                                                &lt;br /&gt;
    }         &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The delete_instance function is called when a plugin is deleted. Note only database records need to be cleaned up - files belonging to fileareas for this assignment will be automatically cleaned up.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    public function format_for_gradebook(stdClass $grade) {                                                                         &lt;br /&gt;
        return FORMAT_MOODLE;                                                                                                       &lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function text_for_gradebook(stdClass $grade) {                                                                           &lt;br /&gt;
        return &#039;&#039;;                                                                                                                  &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Only one feedback plugin can push comments to the gradebook. Usually this is the feedback_comments plugin - but it can be configured to be any feedback plugin. If the current plugin is the plugin chosen to generate comments for the gradebook, the comment text and format will be taken from these two functions.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   /**                                                                                                                             &lt;br /&gt;
     * Override to indicate a plugin supports quickgrading                                                                          &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @return boolean - True if the plugin supports quickgrading                                                                   &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function supports_quickgrading() {                                                                                       &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    /**                                                                                                                             &lt;br /&gt;
     * Get quickgrading form elements as html                                                                                       &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @param int $userid The user id in the table this quickgrading element relates to                                             &lt;br /&gt;
     * @param mixed $grade grade or null - The grade data. May be null if there are no grades for this user (yet)                   &lt;br /&gt;
     * @return mixed - A html string containing the html form elements required for quickgrading or false to indicate this plugin does not support quickgrading&lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function get_quickgrading_html($userid, $grade) {                                                                        &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    /**                                                                                                                             &lt;br /&gt;
     * Has the plugin quickgrading form element been modified in the current form submission?                                       &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @param int $userid The user id in the table this quickgrading element relates to                                             &lt;br /&gt;
     * @param stdClass $grade The grade                                                                                             &lt;br /&gt;
     * @return boolean - true if the quickgrading form element has been modified                                                    &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function is_quickgrading_modified($userid, $grade) {                                                                     &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                                                                                                               &lt;br /&gt;
                                                                                                                                    &lt;br /&gt;
    /**                                                                                                                             &lt;br /&gt;
     * Save quickgrading changes                                                                                                    &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @param int $userid The user id in the table this quickgrading element relates to                                             &lt;br /&gt;
     * @param stdClass $grade The grade                                                                                             &lt;br /&gt;
     * @return boolean - true if the grade changes were saved correctly                                                             &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function save_quickgrading_changes($userid, $grade) {                                                                    &lt;br /&gt;
        return false;                                                                                                               &lt;br /&gt;
    }                                &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These 4 functions can be implemented to allow a plugin to support quickgrading. The feedback comments plugin is the only example of this in core. &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
    /**                                                                                                                             &lt;br /&gt;
     * Run cron for this plugin                                                                                                     &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public static function cron() {                                                                                                 &lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
A plugin can run code when cron runs by implementing this method.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   /**                                                                                                                             &lt;br /&gt;
     * Return a list of the grading actions supported by this plugin.                                                               &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * A grading action is a page that is not specific to a user but to the whole assignment.                                       &lt;br /&gt;
     * @return array - An array of action and description strings.                                                                  &lt;br /&gt;
     *                 The action will be passed to grading_action.                                                                 &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function get_grading_actions() {                                                                                         &lt;br /&gt;
        return array();                                                                                                             &lt;br /&gt;
    }                  &lt;br /&gt;
&lt;br /&gt;
   /**                                                                                                                             &lt;br /&gt;
     * Show a grading action form                                                                                                   &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @param string $gradingaction The action chosen from the grading actions menu                                                 &lt;br /&gt;
     * @return string The page containing the form                                                                                  &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function grading_action($gradingaction) {                                                                                &lt;br /&gt;
        return &#039;&#039;;                                                                                                                  &lt;br /&gt;
    }              &lt;br /&gt;
&amp;lt;/pre&amp;gt;       &lt;br /&gt;
&lt;br /&gt;
Grading actions appear in the select menu above the grading table and apply to the whole assignment. An example is &amp;quot;Upload grading worksheet&amp;quot;. When a grading action is selected, the grading_action will be called with the action that was chosen (so plugins can have multiple entries in the list).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
   /**                                                                                                                             &lt;br /&gt;
     * Return a list of the batch grading operations supported by this plugin.                                                      &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @return array - An array of action and description strings.                                                                  &lt;br /&gt;
     *                 The action will be passed to grading_batch_operation.                                                        &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function get_grading_batch_operations() {                                                                                &lt;br /&gt;
        return array();                                                                                                             &lt;br /&gt;
    }     &lt;br /&gt;
&lt;br /&gt;
    /**                                                                                                                             &lt;br /&gt;
     * Show a batch operations form                                                                                                 &lt;br /&gt;
     *                                                                                                                              &lt;br /&gt;
     * @param string $action The action chosen from the batch operations menu                                                       &lt;br /&gt;
     * @param array $users The list of selected userids                                                                             &lt;br /&gt;
     * @return string The page containing the form                                                                                  &lt;br /&gt;
     */                                                                                                                             &lt;br /&gt;
    public function grading_batch_operation($action, $users) {                                                                      &lt;br /&gt;
        return &#039;&#039;;                                                                                                                  &lt;br /&gt;
    }              &lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
These two callbacks allow adding entries to the batch grading operations list (where you select multiple users in the table and choose e.g. &amp;quot;Lock submissions&amp;quot; for every user). The action is passed to &amp;quot;grading_batch_operation&amp;quot; so that multiple entries can be supported by a plugin.&lt;br /&gt;
&lt;br /&gt;
== Other features ==&lt;br /&gt;
&lt;br /&gt;
=== Add calendar events ===&lt;br /&gt;
&lt;br /&gt;
{{Moodle 3.1}}&lt;br /&gt;
&lt;br /&gt;
From Moodle 3.1 onwards, feedback plugins can add events to the Moodle calendar without side effects. These will be hidden and deleted in line with the assignment module. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
        // Add release date to calendar&lt;br /&gt;
        $calendarevent = new stdClass();&lt;br /&gt;
        $calendarevent-&amp;gt;name         = get_string(&#039;calendareventname&#039;, &#039;assignsubmission_something&#039;);&lt;br /&gt;
        $calendarevent-&amp;gt;description  = get_string(&#039;calendareventdesc&#039;, &#039;assignsubmission_something&#039;);&lt;br /&gt;
        $calendarevent-&amp;gt;courseid     = $courseid;&lt;br /&gt;
        $calendarevent-&amp;gt;groupid      = 0;&lt;br /&gt;
        $calendarevent-&amp;gt;userid       = $userid;&lt;br /&gt;
        $calendarevent-&amp;gt;modulename   = &#039;assign&#039;;&lt;br /&gt;
        $calendarevent-&amp;gt;instance     = $instanceid;&lt;br /&gt;
        $calendarevent-&amp;gt;eventtype    = &#039;something_release&#039;; // For activity module&#039;s events, this can be used to set the alternative text of the event icon. Set it to &#039;pluginname&#039; unless you have a better string.&lt;br /&gt;
        $calendarevent-&amp;gt;timestart    = $releasedate;&lt;br /&gt;
        $calendarevent-&amp;gt;visible      = true;&lt;br /&gt;
        $calendarevent-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
        calendar_event::create($calendarevent);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=58164</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=58164"/>
		<updated>2020-12-09T11:32:16Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Update script to include MOODLE_311_STABLE&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..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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=57797</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=57797"/>
		<updated>2020-08-24T20:21:58Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Revised script for 3.10 branch, see https://moodle.org/mod/forum/discuss.php?d=409100#p1651083&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..39}_STABLE MOODLE_310_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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=57793</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=57793"/>
		<updated>2020-08-24T11:55:38Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Update script to support MOODLE_310_STABLE. See https://moodle.org/mod/forum/discuss.php?d=409100 for info&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;
    branches=(&amp;quot;19&amp;quot; &amp;quot;20&amp;quot; &amp;quot;21&amp;quot; &amp;quot;22&amp;quot; &amp;quot;23&amp;quot; &amp;quot;24&amp;quot; &amp;quot;25&amp;quot; &amp;quot;26&amp;quot; &amp;quot;27&amp;quot; &amp;quot;28&amp;quot; &amp;quot;29&amp;quot; \&lt;br /&gt;
          &amp;quot;30&amp;quot; &amp;quot;31&amp;quot; &amp;quot;32&amp;quot; &amp;quot;33&amp;quot; &amp;quot;34&amp;quot; &amp;quot;35&amp;quot; &amp;quot;36&amp;quot; &amp;quot;37&amp;quot; &amp;quot;38&amp;quot; &amp;quot;39&amp;quot; &amp;quot;310&amp;quot;)&lt;br /&gt;
    branches=(&amp;quot;${branches[@]/#/MOODLE_}&amp;quot;)&lt;br /&gt;
    branches=(&amp;quot;${branches[@]/%/_STABLE}&amp;quot;)&lt;br /&gt;
    for BRANCH in &amp;quot;${branches[@]}&amp;quot; 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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=57611</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=57611"/>
		<updated>2020-06-16T11:17:53Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Updated script to include MOODLE_39_STABLE)&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..39}_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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=57588</id>
		<title>Creating a theme based on boost</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=57588"/>
		<updated>2020-06-12T11:47:45Z</updated>

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

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */  Updated script to include MOODLE_38_STABLE&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..38}_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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=55468</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=55468"/>
		<updated>2019-01-17T17:28:22Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Updated script to include MOODLE_36_STABLE&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..36}_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>Leonstr</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Git_for_developers&amp;diff=54271</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=54271"/>
		<updated>2018-05-22T16:22:28Z</updated>

		<summary type="html">&lt;p&gt;Leonstr: /* Keeping your public repository up-to-date */ Updated for recently-released MOODLE_35_STABLE branch&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..35}_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;
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-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>Leonstr</name></author>
	</entry>
</feed>