<?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=Systemovich</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=Systemovich"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Systemovich"/>
	<updated>2026-06-06T21:10:52Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Form_API&amp;diff=61700</id>
		<title>Form API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Form_API&amp;diff=61700"/>
		<updated>2022-02-04T09:48:16Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* Usage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
[https://en.wikipedia.org/wiki/Form_(HTML) Web forms] in Moodle are created using the Form API. The Form API supports all HTML elements (checkboxes, radio buttons, text boxes, etc), with improved accessibility and security.&lt;br /&gt;
==Highlights==&lt;br /&gt;
# Tested and optimised for use on major screen-readers like Dragon and JAWS.&lt;br /&gt;
# Tableless layout.&lt;br /&gt;
# Processes form data securely, with required_param, optional_param and session key.&lt;br /&gt;
# Supports client-side validation.&lt;br /&gt;
# Facility to add Moodle help buttons to forms. &lt;br /&gt;
# Support for file repository using [[File_API]] .&lt;br /&gt;
# Support for many custom Moodle specific and non-specific form elements.&lt;br /&gt;
# Facility for [https://docs.moodle.org/dev/lib/formslib.php_repeat_elements repeated elements].&lt;br /&gt;
# Facility for form elements in advanced group&lt;br /&gt;
==Usage==&lt;br /&gt;
To create a form in Moodle, you have to create a class that extends the moodleform class and overrides the [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#definition.28.29 definition]  member function for including form elements.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//moodleform is defined in formslib.php&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;
    //Add elements to form&lt;br /&gt;
    public 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(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;)); // Add elements to your form.&lt;br /&gt;
        $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);                   // Set type of element.&lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;email&#039;, &#039;Please enter email&#039;);        // Default value.&lt;br /&gt;
            ...&lt;br /&gt;
    }&lt;br /&gt;
    //Custom validation should be added here&lt;br /&gt;
    function validation($data, $files) {&lt;br /&gt;
        return array();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then instantiate the form (in this case simplehtml_form) on your page.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//include simplehtml_form.php&lt;br /&gt;
require_once(&#039;PATH_TO/simplehtml_form.php&#039;);&lt;br /&gt;
&lt;br /&gt;
//Instantiate simplehtml_form &lt;br /&gt;
$mform = new simplehtml_form();&lt;br /&gt;
&lt;br /&gt;
//Form processing and displaying is done here&lt;br /&gt;
if ($mform-&amp;gt;is_cancelled()) {&lt;br /&gt;
    //Handle form cancel operation, if cancel button is present on form&lt;br /&gt;
} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
  //In this case you process validated data. $mform-&amp;gt;get_data() returns data posted in form.&lt;br /&gt;
} else {&lt;br /&gt;
  // this branch is executed if the form is submitted but the data doesn&#039;t validate and the form should be redisplayed&lt;br /&gt;
  // or on the first display of the form.&lt;br /&gt;
&lt;br /&gt;
  //Set default data (if any)&lt;br /&gt;
  $mform-&amp;gt;set_data($toform);&lt;br /&gt;
  //displays the form&lt;br /&gt;
  $mform-&amp;gt;display();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you wish to use the form within a block then you should consider using the render method, as demonstrated below:&lt;br /&gt;
&lt;br /&gt;
Note that the render method does the same as the display method, except returning the HTML rather than outputting it to the browser, as with above make sure you&#039;ve included the file which contains the class for your Moodle form.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class block_yourblock extends block_base{&lt;br /&gt;
	public function init(){&lt;br /&gt;
		$this-&amp;gt;title = &#039;Your Block&#039;;&lt;br /&gt;
	}&lt;br /&gt;
	public function get_content(){&lt;br /&gt;
&lt;br /&gt;
		$this-&amp;gt;content = new stdClass();&lt;br /&gt;
		$this-&amp;gt;content-&amp;gt;text = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
		$mform = new simplehtml_form();&lt;br /&gt;
&lt;br /&gt;
		//Form processing and displaying is done here&lt;br /&gt;
		if ($mform-&amp;gt;is_cancelled()) {&lt;br /&gt;
			//Handle form cancel operation, if cancel button is present on form&lt;br /&gt;
		} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
			//In this case you process validated data. $mform-&amp;gt;get_data() returns data posted in form.&lt;br /&gt;
		} else {&lt;br /&gt;
			// this branch is executed if the form is submitted but the data doesn&#039;t validate and the form should be redisplayed&lt;br /&gt;
			// or on the first display of the form.&lt;br /&gt;
&lt;br /&gt;
			//Set default data (if any)&lt;br /&gt;
			$mform-&amp;gt;set_data($toform);&lt;br /&gt;
&lt;br /&gt;
			//displays the form&lt;br /&gt;
			$this-&amp;gt;content-&amp;gt;text = $mform-&amp;gt;render();&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		return $this-&amp;gt;content;&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Form elements==&lt;br /&gt;
===Basic form elements===&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#button button]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#checkbox checkbox]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#radio radio]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#select select]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#multi-select multi-select]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#password password]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#hidden hidden]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#html html] - div element&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#static static] - Display a static text.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#text text]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#textarea textarea]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#Use_Fieldsets_to_group_Form_Elements header]&lt;br /&gt;
=== Advanced form elements===&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#autocomplete Autocomplete] - A select box that allows you to start typing to narrow the list of options, or search for results.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#advcheckbox advcheckbox] - Advance checkbox&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#float float]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#passwordunmask passwordunmask] - A password element with option to show the password in plaintext.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#recaptcha recaptcha]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#selectyesno selectyesno]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#selectwithlink selectwithlink]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#date_selector date_selector]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#date_time_selector date_time_selector]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#duration duration]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#editor editor]&lt;br /&gt;
# [https://docs.moodle.org/dev/Using_the_File_API_in_Moodle_forms#filepicker filepicker] - upload single file&lt;br /&gt;
# [https://docs.moodle.org/dev/Using_the_File_API_in_Moodle_forms#filemanager filemanager] - upload multiple files&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#tags tags]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#addGroup addGroup]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#modgrade modgrade]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#modvisible modvisible]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#choosecoursefile choosecoursefile]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#grading grading]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#questioncategory questioncategory]&lt;br /&gt;
===Custom form elements===&lt;br /&gt;
If you need a custom form element you can dynamical register new elements and then use them like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    MoodleQuickForm::registerElementType(&#039;course_competency_rule&#039;,&lt;br /&gt;
                                         &amp;quot;$CFG-&amp;gt;dirroot/$CFG-&amp;gt;admin/tool/lp/classes/course_competency_rule_form_element.php&amp;quot;,&lt;br /&gt;
                                         &#039;tool_lp_course_competency_rule_form_element&#039;);&lt;br /&gt;
    // Reuse the same options.&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course_competency_rule&#039;, &#039;competency_rule&#039;, get_string(&#039;uponcoursemodulecompletion&#039;, &#039;tool_lp&#039;), $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See:&lt;br /&gt;
&lt;br /&gt;
https://github.com/moodle/moodle/blob/master/admin/tool/lp/lib.php#L157-L161&lt;br /&gt;
&lt;br /&gt;
https://github.com/moodle/moodle/blob/master/admin/tool/lp/classes/course_competency_rule_form_element.php&lt;br /&gt;
==Commonly used functions==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   $this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#setDefault_2|setDefault()]]====&lt;br /&gt;
To set the default value for an element.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#disabledIf|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;
====[[lib/formslib.php_Form_Definition#hideIf|hideif()]]====&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;
Same syntax as disabledIf. Can do a simple search and replace on disabledIf. Added in Moodle 3.4.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#addRule|addRule()]]====&lt;br /&gt;
Add rule for server/client side validation. Like text field is required element and is of type email.&lt;br /&gt;
====setHelpButton()====&lt;br /&gt;
DEPRECATED - Sets pop-up help button to a form element. Use addHelpButton() instead.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#addHelpButton|addHelpButton()]]====&lt;br /&gt;
Adds pop-up help button to a form element&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#setType|setType()]]====&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#disable_form_change_checker|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 &amp;lt;tt&amp;gt;$mform-&amp;gt;disable_form_change_checker()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
==FAQ==&lt;br /&gt;
[https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#Use_Fieldsets_to_group_Form_Elements How to group elements]&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core_APIs]]&lt;br /&gt;
* [[lib/formslib.php_Usage]] &lt;br /&gt;
* [[lib/formslib.php_Form_Definition]]&lt;br /&gt;
* [[Designing usable forms]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
* [[MForm_Modal]]&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Form_API&amp;diff=61699</id>
		<title>Form API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Form_API&amp;diff=61699"/>
		<updated>2022-02-04T09:37:36Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* Highlights */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
[https://en.wikipedia.org/wiki/Form_(HTML) Web forms] in Moodle are created using the Form API. The Form API supports all HTML elements (checkboxes, radio buttons, text boxes, etc), with improved accessibility and security.&lt;br /&gt;
==Highlights==&lt;br /&gt;
# Tested and optimised for use on major screen-readers like Dragon and JAWS.&lt;br /&gt;
# Tableless layout.&lt;br /&gt;
# Processes form data securely, with required_param, optional_param and session key.&lt;br /&gt;
# Supports client-side validation.&lt;br /&gt;
# Facility to add Moodle help buttons to forms. &lt;br /&gt;
# Support for file repository using [[File_API]] .&lt;br /&gt;
# Support for many custom Moodle specific and non-specific form elements.&lt;br /&gt;
# Facility for [https://docs.moodle.org/dev/lib/formslib.php_repeat_elements repeated elements].&lt;br /&gt;
# Facility for form elements in advanced group&lt;br /&gt;
==Usage==&lt;br /&gt;
For creating a form in moodle, you have to create class extending moodleform class and override [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#definition.28.29 definition] for including form elements.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//moodleform is defined in formslib.php&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;
    //Add elements to form&lt;br /&gt;
    public 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(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;)); // Add elements to your form&lt;br /&gt;
        $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);                   //Set type of element&lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;email&#039;, &#039;Please enter email&#039;);        //Default value&lt;br /&gt;
            ...&lt;br /&gt;
    }&lt;br /&gt;
    //Custom validation should be added here&lt;br /&gt;
    function validation($data, $files) {&lt;br /&gt;
        return array();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then instantiate form (in this case simplehtml_form) on your page.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//include simplehtml_form.php&lt;br /&gt;
require_once(&#039;PATH_TO/simplehtml_form.php&#039;);&lt;br /&gt;
&lt;br /&gt;
//Instantiate simplehtml_form &lt;br /&gt;
$mform = new simplehtml_form();&lt;br /&gt;
&lt;br /&gt;
//Form processing and displaying is done here&lt;br /&gt;
if ($mform-&amp;gt;is_cancelled()) {&lt;br /&gt;
    //Handle form cancel operation, if cancel button is present on form&lt;br /&gt;
} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
  //In this case you process validated data. $mform-&amp;gt;get_data() returns data posted in form.&lt;br /&gt;
} else {&lt;br /&gt;
  // this branch is executed if the form is submitted but the data doesn&#039;t validate and the form should be redisplayed&lt;br /&gt;
  // or on the first display of the form.&lt;br /&gt;
&lt;br /&gt;
  //Set default data (if any)&lt;br /&gt;
  $mform-&amp;gt;set_data($toform);&lt;br /&gt;
  //displays the form&lt;br /&gt;
  $mform-&amp;gt;display();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you wish to use the form within a block then you should consider using the render method, as demonstrated below:&lt;br /&gt;
&lt;br /&gt;
Note that the render method does the same as the display method, except returning the HTML rather than outputting it to the browser, as with above make sure you&#039;ve included the file which contains the class for your Moodle form.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class block_yourblock extends block_base{&lt;br /&gt;
	public function init(){&lt;br /&gt;
		$this-&amp;gt;title = &#039;Your Block&#039;;&lt;br /&gt;
	}&lt;br /&gt;
	public function get_content(){&lt;br /&gt;
&lt;br /&gt;
		$this-&amp;gt;content = new stdClass();&lt;br /&gt;
		$this-&amp;gt;content-&amp;gt;text = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
		$mform = new simplehtml_form();&lt;br /&gt;
&lt;br /&gt;
		//Form processing and displaying is done here&lt;br /&gt;
		if ($mform-&amp;gt;is_cancelled()) {&lt;br /&gt;
			//Handle form cancel operation, if cancel button is present on form&lt;br /&gt;
		} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
			//In this case you process validated data. $mform-&amp;gt;get_data() returns data posted in form.&lt;br /&gt;
		} else {&lt;br /&gt;
			// this branch is executed if the form is submitted but the data doesn&#039;t validate and the form should be redisplayed&lt;br /&gt;
			// or on the first display of the form.&lt;br /&gt;
&lt;br /&gt;
			//Set default data (if any)&lt;br /&gt;
			$mform-&amp;gt;set_data($toform);&lt;br /&gt;
&lt;br /&gt;
			//displays the form&lt;br /&gt;
			$this-&amp;gt;content-&amp;gt;text = $mform-&amp;gt;render();&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		return $this-&amp;gt;content;&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Form elements==&lt;br /&gt;
===Basic form elements===&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#button button]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#checkbox checkbox]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#radio radio]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#select select]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#multi-select multi-select]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#password password]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#hidden hidden]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#html html] - div element&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#static static] - Display a static text.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#text text]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#textarea textarea]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#Use_Fieldsets_to_group_Form_Elements header]&lt;br /&gt;
=== Advanced form elements===&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#autocomplete Autocomplete] - A select box that allows you to start typing to narrow the list of options, or search for results.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#advcheckbox advcheckbox] - Advance checkbox&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#float float]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#passwordunmask passwordunmask] - A password element with option to show the password in plaintext.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#recaptcha recaptcha]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#selectyesno selectyesno]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#selectwithlink selectwithlink]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#date_selector date_selector]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#date_time_selector date_time_selector]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#duration duration]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#editor editor]&lt;br /&gt;
# [https://docs.moodle.org/dev/Using_the_File_API_in_Moodle_forms#filepicker filepicker] - upload single file&lt;br /&gt;
# [https://docs.moodle.org/dev/Using_the_File_API_in_Moodle_forms#filemanager filemanager] - upload multiple files&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#tags tags]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#addGroup addGroup]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#modgrade modgrade]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#modvisible modvisible]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#choosecoursefile choosecoursefile]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#grading grading]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#questioncategory questioncategory]&lt;br /&gt;
===Custom form elements===&lt;br /&gt;
If you need a custom form element you can dynamical register new elements and then use them like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    MoodleQuickForm::registerElementType(&#039;course_competency_rule&#039;,&lt;br /&gt;
                                         &amp;quot;$CFG-&amp;gt;dirroot/$CFG-&amp;gt;admin/tool/lp/classes/course_competency_rule_form_element.php&amp;quot;,&lt;br /&gt;
                                         &#039;tool_lp_course_competency_rule_form_element&#039;);&lt;br /&gt;
    // Reuse the same options.&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course_competency_rule&#039;, &#039;competency_rule&#039;, get_string(&#039;uponcoursemodulecompletion&#039;, &#039;tool_lp&#039;), $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See:&lt;br /&gt;
&lt;br /&gt;
https://github.com/moodle/moodle/blob/master/admin/tool/lp/lib.php#L157-L161&lt;br /&gt;
&lt;br /&gt;
https://github.com/moodle/moodle/blob/master/admin/tool/lp/classes/course_competency_rule_form_element.php&lt;br /&gt;
==Commonly used functions==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   $this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#setDefault_2|setDefault()]]====&lt;br /&gt;
To set the default value for an element.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#disabledIf|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;
====[[lib/formslib.php_Form_Definition#hideIf|hideif()]]====&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;
Same syntax as disabledIf. Can do a simple search and replace on disabledIf. Added in Moodle 3.4.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#addRule|addRule()]]====&lt;br /&gt;
Add rule for server/client side validation. Like text field is required element and is of type email.&lt;br /&gt;
====setHelpButton()====&lt;br /&gt;
DEPRECATED - Sets pop-up help button to a form element. Use addHelpButton() instead.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#addHelpButton|addHelpButton()]]====&lt;br /&gt;
Adds pop-up help button to a form element&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#setType|setType()]]====&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#disable_form_change_checker|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 &amp;lt;tt&amp;gt;$mform-&amp;gt;disable_form_change_checker()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
==FAQ==&lt;br /&gt;
[https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#Use_Fieldsets_to_group_Form_Elements How to group elements]&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core_APIs]]&lt;br /&gt;
* [[lib/formslib.php_Usage]] &lt;br /&gt;
* [[lib/formslib.php_Form_Definition]]&lt;br /&gt;
* [[Designing usable forms]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
* [[MForm_Modal]]&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Form_API&amp;diff=61698</id>
		<title>Form API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Form_API&amp;diff=61698"/>
		<updated>2022-02-04T09:34:13Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* Overview */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Overview==&lt;br /&gt;
[https://en.wikipedia.org/wiki/Form_(HTML) Web forms] in Moodle are created using the Form API. The Form API supports all HTML elements (checkboxes, radio buttons, text boxes, etc), with improved accessibility and security.&lt;br /&gt;
==Highlights==&lt;br /&gt;
# Tested and optimised for use on major screen-readers Dragon and JAWS. &lt;br /&gt;
# Tableless layout.&lt;br /&gt;
# Process form data securely, with required_param, optional_param and session key.&lt;br /&gt;
# Supports client-side validation&lt;br /&gt;
# Facility to add Moodle help buttons to forms. &lt;br /&gt;
# Support for file repository using [[File_API]]&lt;br /&gt;
# Support for many custom moodle specific and non-specific form elements.&lt;br /&gt;
# Addition for [https://docs.moodle.org/dev/lib/formslib.php_repeat_elements repeated elements].&lt;br /&gt;
# Addition for form elements in advance group&lt;br /&gt;
==Usage==&lt;br /&gt;
For creating a form in moodle, you have to create class extending moodleform class and override [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#definition.28.29 definition] for including form elements.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//moodleform is defined in formslib.php&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;
    //Add elements to form&lt;br /&gt;
    public 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(&#039;text&#039;, &#039;email&#039;, get_string(&#039;email&#039;)); // Add elements to your form&lt;br /&gt;
        $mform-&amp;gt;setType(&#039;email&#039;, PARAM_NOTAGS);                   //Set type of element&lt;br /&gt;
        $mform-&amp;gt;setDefault(&#039;email&#039;, &#039;Please enter email&#039;);        //Default value&lt;br /&gt;
            ...&lt;br /&gt;
    }&lt;br /&gt;
    //Custom validation should be added here&lt;br /&gt;
    function validation($data, $files) {&lt;br /&gt;
        return array();&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
Then instantiate form (in this case simplehtml_form) on your page.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
//include simplehtml_form.php&lt;br /&gt;
require_once(&#039;PATH_TO/simplehtml_form.php&#039;);&lt;br /&gt;
&lt;br /&gt;
//Instantiate simplehtml_form &lt;br /&gt;
$mform = new simplehtml_form();&lt;br /&gt;
&lt;br /&gt;
//Form processing and displaying is done here&lt;br /&gt;
if ($mform-&amp;gt;is_cancelled()) {&lt;br /&gt;
    //Handle form cancel operation, if cancel button is present on form&lt;br /&gt;
} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
  //In this case you process validated data. $mform-&amp;gt;get_data() returns data posted in form.&lt;br /&gt;
} else {&lt;br /&gt;
  // this branch is executed if the form is submitted but the data doesn&#039;t validate and the form should be redisplayed&lt;br /&gt;
  // or on the first display of the form.&lt;br /&gt;
&lt;br /&gt;
  //Set default data (if any)&lt;br /&gt;
  $mform-&amp;gt;set_data($toform);&lt;br /&gt;
  //displays the form&lt;br /&gt;
  $mform-&amp;gt;display();&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
If you wish to use the form within a block then you should consider using the render method, as demonstrated below:&lt;br /&gt;
&lt;br /&gt;
Note that the render method does the same as the display method, except returning the HTML rather than outputting it to the browser, as with above make sure you&#039;ve included the file which contains the class for your Moodle form.&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
class block_yourblock extends block_base{&lt;br /&gt;
	public function init(){&lt;br /&gt;
		$this-&amp;gt;title = &#039;Your Block&#039;;&lt;br /&gt;
	}&lt;br /&gt;
	public function get_content(){&lt;br /&gt;
&lt;br /&gt;
		$this-&amp;gt;content = new stdClass();&lt;br /&gt;
		$this-&amp;gt;content-&amp;gt;text = &#039;&#039;;&lt;br /&gt;
&lt;br /&gt;
		$mform = new simplehtml_form();&lt;br /&gt;
&lt;br /&gt;
		//Form processing and displaying is done here&lt;br /&gt;
		if ($mform-&amp;gt;is_cancelled()) {&lt;br /&gt;
			//Handle form cancel operation, if cancel button is present on form&lt;br /&gt;
		} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
			//In this case you process validated data. $mform-&amp;gt;get_data() returns data posted in form.&lt;br /&gt;
		} else {&lt;br /&gt;
			// this branch is executed if the form is submitted but the data doesn&#039;t validate and the form should be redisplayed&lt;br /&gt;
			// or on the first display of the form.&lt;br /&gt;
&lt;br /&gt;
			//Set default data (if any)&lt;br /&gt;
			$mform-&amp;gt;set_data($toform);&lt;br /&gt;
&lt;br /&gt;
			//displays the form&lt;br /&gt;
			$this-&amp;gt;content-&amp;gt;text = $mform-&amp;gt;render();&lt;br /&gt;
		}&lt;br /&gt;
&lt;br /&gt;
		return $this-&amp;gt;content;&lt;br /&gt;
&lt;br /&gt;
	}&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
==Form elements==&lt;br /&gt;
===Basic form elements===&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#button button]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#checkbox checkbox]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#radio radio]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#select select]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#multi-select multi-select]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#password password]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#hidden hidden]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#html html] - div element&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#static static] - Display a static text.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#text text]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#textarea textarea]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#Use_Fieldsets_to_group_Form_Elements header]&lt;br /&gt;
=== Advanced form elements===&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#autocomplete Autocomplete] - A select box that allows you to start typing to narrow the list of options, or search for results.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#advcheckbox advcheckbox] - Advance checkbox&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#float float]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#passwordunmask passwordunmask] - A password element with option to show the password in plaintext.&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#recaptcha recaptcha]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#selectyesno selectyesno]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#selectwithlink selectwithlink]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#date_selector date_selector]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#date_time_selector date_time_selector]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#duration duration]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#editor editor]&lt;br /&gt;
# [https://docs.moodle.org/dev/Using_the_File_API_in_Moodle_forms#filepicker filepicker] - upload single file&lt;br /&gt;
# [https://docs.moodle.org/dev/Using_the_File_API_in_Moodle_forms#filemanager filemanager] - upload multiple files&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#tags tags]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#addGroup addGroup]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#modgrade modgrade]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#modvisible modvisible]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#choosecoursefile choosecoursefile]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#grading grading]&lt;br /&gt;
# [https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#questioncategory questioncategory]&lt;br /&gt;
===Custom form elements===&lt;br /&gt;
If you need a custom form element you can dynamical register new elements and then use them like this:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
    MoodleQuickForm::registerElementType(&#039;course_competency_rule&#039;,&lt;br /&gt;
                                         &amp;quot;$CFG-&amp;gt;dirroot/$CFG-&amp;gt;admin/tool/lp/classes/course_competency_rule_form_element.php&amp;quot;,&lt;br /&gt;
                                         &#039;tool_lp_course_competency_rule_form_element&#039;);&lt;br /&gt;
    // Reuse the same options.&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;course_competency_rule&#039;, &#039;competency_rule&#039;, get_string(&#039;uponcoursemodulecompletion&#039;, &#039;tool_lp&#039;), $options);&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
See:&lt;br /&gt;
&lt;br /&gt;
https://github.com/moodle/moodle/blob/master/admin/tool/lp/lib.php#L157-L161&lt;br /&gt;
&lt;br /&gt;
https://github.com/moodle/moodle/blob/master/admin/tool/lp/classes/course_competency_rule_form_element.php&lt;br /&gt;
==Commonly used functions==&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;syntaxhighlight lang=&amp;quot;php&amp;quot;&amp;gt;&lt;br /&gt;
   $this-&amp;gt;add_action_buttons();&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#setDefault_2|setDefault()]]====&lt;br /&gt;
To set the default value for an element.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#disabledIf|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;
====[[lib/formslib.php_Form_Definition#hideIf|hideif()]]====&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;
Same syntax as disabledIf. Can do a simple search and replace on disabledIf. Added in Moodle 3.4.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#addRule|addRule()]]====&lt;br /&gt;
Add rule for server/client side validation. Like text field is required element and is of type email.&lt;br /&gt;
====setHelpButton()====&lt;br /&gt;
DEPRECATED - Sets pop-up help button to a form element. Use addHelpButton() instead.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#addHelpButton|addHelpButton()]]====&lt;br /&gt;
Adds pop-up help button to a form element&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#setType|setType()]]====&lt;br /&gt;
PARAM_* types are used to specify how a submitted variable should be cleaned.&lt;br /&gt;
====[[lib/formslib.php_Form_Definition#disable_form_change_checker|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 &amp;lt;tt&amp;gt;$mform-&amp;gt;disable_form_change_checker()&amp;lt;/tt&amp;gt;.&lt;br /&gt;
==FAQ==&lt;br /&gt;
[https://docs.moodle.org/dev/lib/formslib.php_Form_Definition#Use_Fieldsets_to_group_Form_Elements How to group elements]&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core_APIs]]&lt;br /&gt;
* [[lib/formslib.php_Usage]] &lt;br /&gt;
* [[lib/formslib.php_Form_Definition]]&lt;br /&gt;
* [[Designing usable forms]]&lt;br /&gt;
* [[Fragment]]&lt;br /&gt;
* [[MForm_Modal]]&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58600</id>
		<title>User profile fields</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58600"/>
		<updated>2021-03-26T09:44:07Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* define_validate_specific() */ Added full stop.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This plugin allows you to add custom user profile field types of which instances can be added to the user profile. For example, if you want to display radio buttons on the user profile, then create a radio user profile field plugin, then create an instance of it.&lt;br /&gt;
==History==&lt;br /&gt;
User profile fields exist from  Moodle 1.9 and support five default user profile field plugins:&lt;br /&gt;
# checkbox&lt;br /&gt;
# datetime&lt;br /&gt;
# menu&lt;br /&gt;
# text&lt;br /&gt;
# textarea&lt;br /&gt;
&lt;br /&gt;
==File Structure==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/user/profile/field/customprofilefieldplugin&#039;&#039;. The folder name should contain only letters and numbers.&lt;br /&gt;
# Create the following files and add them to customprofilefieldplugin:&lt;br /&gt;
## &#039;&#039;lang/en/profilefield_customprofilefieldplugin.php&#039;&#039; - Language file, containing strings for user profile field.&lt;br /&gt;
## &#039;&#039;define.class.php&#039;&#039; - Definition of the user profile field type will be added in this file.&lt;br /&gt;
## &#039;&#039;field.class.php&#039;&#039; - Controls user profile field display, while editing or showing as user profile field.&lt;br /&gt;
## &#039;&#039;version.php&#039;&#039; - Contains version information for customprofilefieldplugin.&lt;br /&gt;
&lt;br /&gt;
==Naming convention==&lt;br /&gt;
# &#039;&#039;&#039;profilefield_&#039;&#039;&#039; is prefixed to the name of the user profile field plugin, for identifying the name of the plugin.&lt;br /&gt;
# &#039;&#039;define.class.php&#039;&#039; should contain a class with a name that has &#039;&#039;&#039;profile_define_&#039;&#039;&#039; prefixed to the custom user profile field plugin name.&lt;br /&gt;
# &#039;&#039;field.class.php&#039;&#039; should contain a class with a name that has &#039;&#039;&#039;profile_field_&#039;&#039;&#039; prefixed to the custom user profile field plugin name.&lt;br /&gt;
# The language file should define a &#039;&#039;&#039;pluginname&#039;&#039;&#039; string as the name of the plugin.&lt;br /&gt;
&lt;br /&gt;
==Interface API==&lt;br /&gt;
===define.class.php===&lt;br /&gt;
====define_form_specific()====&lt;br /&gt;
Prints out the form snippet for the part of creating or editing a profile field specific to the current data type.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_form_specific(&amp;amp;$form) {&lt;br /&gt;
   // select whether or not this should be checked by default&lt;br /&gt;
   $form-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;defaultdata&#039;, get_string(&#039;label&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   $form-&amp;gt;setDefault(&#039;defaultdata&#039;, 0); // defaults to &#039;no&#039;&lt;br /&gt;
   $form-&amp;gt;setType(&#039;defaultdata&#039;, PARAM_BOOL);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====define_validate_specific()====&lt;br /&gt;
Validate the data from the add/edit profile field form that is specific to the current data type.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_validate_specific($data) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   // Make sure defaultdata is not false&lt;br /&gt;
   if ($data-&amp;gt;defaultdata == false) {&lt;br /&gt;
      $errors[&#039;defaultdata&#039;] = get_string(&#039;noprovided&#039;, &#039;profilefield_myprofilefield&#039;);&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====define_after_data====&lt;br /&gt;
Alter form based on submitted or existing data&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_after_data(&amp;amp;$form) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;shouldbeyes&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_save_preprocess====&lt;br /&gt;
Pre-process data from the profile field form before it is saved.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_save_preprocess($data) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $data-&amp;gt;defaultdata = NULL;&lt;br /&gt;
   }&lt;br /&gt;
   return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===field.class.php===&lt;br /&gt;
====edit_field_add()====&lt;br /&gt;
Adds the profile field to the moodle form&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_add(&amp;amp;$mform) {&lt;br /&gt;
   // Create form field&lt;br /&gt;
   $checkbox = &amp;amp;$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, $this-&amp;gt;inputname, format_string($this-&amp;gt;field-&amp;gt;name));&lt;br /&gt;
   if ($this-&amp;gt;data == &#039;1&#039;) {&lt;br /&gt;
       $checkbox-&amp;gt;setChecked(true);&lt;br /&gt;
   }&lt;br /&gt;
   $mform-&amp;gt;setType($this-&amp;gt;inputname, PARAM_BOOL);&lt;br /&gt;
   if ($this-&amp;gt;is_required() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
       $mform-&amp;gt;addRule($this-&amp;gt;inputname, get_string(&#039;required&#039;), &#039;nonzero&#039;, null, &#039;client&#039;);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====display_data()====&lt;br /&gt;
Display the data for this field&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function display_data() {&lt;br /&gt;
   $options = new stdClass();&lt;br /&gt;
   $options-&amp;gt;para = false;&lt;br /&gt;
   $checked = intval($this-&amp;gt;data) === 1 ? &#039;checked=&amp;quot;checked&amp;quot;&#039; : &#039;&#039;;&lt;br /&gt;
   return &#039;&amp;lt;input disabled=&amp;quot;disabled&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;&#039;.$this-&amp;gt;inputname.&#039;&amp;quot; &#039;.$checked.&#039; /&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_default()====&lt;br /&gt;
Sets the default data for the field in the form object&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_default(&amp;amp;$mform) {&lt;br /&gt;
   if (!empty($default)) {&lt;br /&gt;
      $mform-&amp;gt;setDefault($this-&amp;gt;inputname, $this-&amp;gt;field-&amp;gt;defaultdata);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_validate_field()====&lt;br /&gt;
Validate the form field from profile page&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_validate_field($usernew) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   if (isset($usernew-&amp;gt;{$this-&amp;gt;inputname})) {&lt;br /&gt;
      if ($usernew-&amp;gt;{$this-&amp;gt;inputname}[&#039;text&#039;] === &#039;&#039;) {&lt;br /&gt;
       $errors[$this-&amp;gt;inputname] = &#039;error&#039;;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====edit_save_data_preprocess()====&lt;br /&gt;
Process the data before it gets saved in database&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_save_data_preprocess($data, &amp;amp;$datarecord) {&lt;br /&gt;
  if (is_array($data)) {&lt;br /&gt;
     $datarecord-&amp;gt;dataformat = $data[&#039;format&#039;];&lt;br /&gt;
     $data = $data[&#039;text&#039;];&lt;br /&gt;
  }&lt;br /&gt;
  return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_locked()====&lt;br /&gt;
HardFreeze the field if locked.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_locked(&amp;amp;$mform) {&lt;br /&gt;
   if (!$mform-&amp;gt;elementExists($this-&amp;gt;inputname)) {&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   if ($this-&amp;gt;is_locked() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
      $mform-&amp;gt;hardFreeze($this-&amp;gt;inputname);&lt;br /&gt;
      $mform-&amp;gt;setConstant($this-&amp;gt;inputname, $this-&amp;gt;data);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Common functions===&lt;br /&gt;
The following will need to be added to any files accessing the profile_ functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;dirroot/user/profile/lib.php&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====profile_user_record($userid)====&lt;br /&gt;
Returns an object with the custom profile fields set for the given user&lt;br /&gt;
====profile_save_data($usernew)====&lt;br /&gt;
Saves custom profile field data&lt;br /&gt;
====profile_validation($usernew, $files)====&lt;br /&gt;
Validates custom user profile field&lt;br /&gt;
&lt;br /&gt;
==Template==&lt;br /&gt;
[https://github.com/rajeshtaneja/userprofilefield user profile field template]&lt;br /&gt;
==Database tables==&lt;br /&gt;
Knowledge of database tables is not required for creating this plugin as, tables get populated when the fields are added to user profile page, by admin. There are two relevant tables for user profile fields:&lt;br /&gt;
# user_info_field - Information for custom field added to user profile page.&lt;br /&gt;
# user_info_data - Data added by user for the custom profile field&lt;br /&gt;
==FAQ==&lt;br /&gt;
===How to add custom user profile field===&lt;br /&gt;
Admin can add existing or custom profile fields. Refer [[:en : User profile fields]] for adding user profile fields to user profile.&lt;br /&gt;
===Which form elements does moodle support===&lt;br /&gt;
Refer [[Form_API]] for list of elements supported by moodle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58599</id>
		<title>User profile fields</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58599"/>
		<updated>2021-03-26T09:43:44Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* define_form_specific() */ Added full stop.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This plugin allows you to add custom user profile field types of which instances can be added to the user profile. For example, if you want to display radio buttons on the user profile, then create a radio user profile field plugin, then create an instance of it.&lt;br /&gt;
==History==&lt;br /&gt;
User profile fields exist from  Moodle 1.9 and support five default user profile field plugins:&lt;br /&gt;
# checkbox&lt;br /&gt;
# datetime&lt;br /&gt;
# menu&lt;br /&gt;
# text&lt;br /&gt;
# textarea&lt;br /&gt;
&lt;br /&gt;
==File Structure==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/user/profile/field/customprofilefieldplugin&#039;&#039;. The folder name should contain only letters and numbers.&lt;br /&gt;
# Create the following files and add them to customprofilefieldplugin:&lt;br /&gt;
## &#039;&#039;lang/en/profilefield_customprofilefieldplugin.php&#039;&#039; - Language file, containing strings for user profile field.&lt;br /&gt;
## &#039;&#039;define.class.php&#039;&#039; - Definition of the user profile field type will be added in this file.&lt;br /&gt;
## &#039;&#039;field.class.php&#039;&#039; - Controls user profile field display, while editing or showing as user profile field.&lt;br /&gt;
## &#039;&#039;version.php&#039;&#039; - Contains version information for customprofilefieldplugin.&lt;br /&gt;
&lt;br /&gt;
==Naming convention==&lt;br /&gt;
# &#039;&#039;&#039;profilefield_&#039;&#039;&#039; is prefixed to the name of the user profile field plugin, for identifying the name of the plugin.&lt;br /&gt;
# &#039;&#039;define.class.php&#039;&#039; should contain a class with a name that has &#039;&#039;&#039;profile_define_&#039;&#039;&#039; prefixed to the custom user profile field plugin name.&lt;br /&gt;
# &#039;&#039;field.class.php&#039;&#039; should contain a class with a name that has &#039;&#039;&#039;profile_field_&#039;&#039;&#039; prefixed to the custom user profile field plugin name.&lt;br /&gt;
# The language file should define a &#039;&#039;&#039;pluginname&#039;&#039;&#039; string as the name of the plugin.&lt;br /&gt;
&lt;br /&gt;
==Interface API==&lt;br /&gt;
===define.class.php===&lt;br /&gt;
====define_form_specific()====&lt;br /&gt;
Prints out the form snippet for the part of creating or editing a profile field specific to the current data type.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_form_specific(&amp;amp;$form) {&lt;br /&gt;
   // select whether or not this should be checked by default&lt;br /&gt;
   $form-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;defaultdata&#039;, get_string(&#039;label&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   $form-&amp;gt;setDefault(&#039;defaultdata&#039;, 0); // defaults to &#039;no&#039;&lt;br /&gt;
   $form-&amp;gt;setType(&#039;defaultdata&#039;, PARAM_BOOL);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====define_validate_specific()====&lt;br /&gt;
Validate the data from the add/edit profile field form that is specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_validate_specific($data) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   // Make sure defaultdata is not false&lt;br /&gt;
   if ($data-&amp;gt;defaultdata == false) {&lt;br /&gt;
      $errors[&#039;defaultdata&#039;] = get_string(&#039;noprovided&#039;, &#039;profilefield_myprofilefield&#039;);&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_after_data====&lt;br /&gt;
Alter form based on submitted or existing data&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_after_data(&amp;amp;$form) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;shouldbeyes&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_save_preprocess====&lt;br /&gt;
Pre-process data from the profile field form before it is saved.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_save_preprocess($data) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $data-&amp;gt;defaultdata = NULL;&lt;br /&gt;
   }&lt;br /&gt;
   return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===field.class.php===&lt;br /&gt;
====edit_field_add()====&lt;br /&gt;
Adds the profile field to the moodle form&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_add(&amp;amp;$mform) {&lt;br /&gt;
   // Create form field&lt;br /&gt;
   $checkbox = &amp;amp;$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, $this-&amp;gt;inputname, format_string($this-&amp;gt;field-&amp;gt;name));&lt;br /&gt;
   if ($this-&amp;gt;data == &#039;1&#039;) {&lt;br /&gt;
       $checkbox-&amp;gt;setChecked(true);&lt;br /&gt;
   }&lt;br /&gt;
   $mform-&amp;gt;setType($this-&amp;gt;inputname, PARAM_BOOL);&lt;br /&gt;
   if ($this-&amp;gt;is_required() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
       $mform-&amp;gt;addRule($this-&amp;gt;inputname, get_string(&#039;required&#039;), &#039;nonzero&#039;, null, &#039;client&#039;);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====display_data()====&lt;br /&gt;
Display the data for this field&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function display_data() {&lt;br /&gt;
   $options = new stdClass();&lt;br /&gt;
   $options-&amp;gt;para = false;&lt;br /&gt;
   $checked = intval($this-&amp;gt;data) === 1 ? &#039;checked=&amp;quot;checked&amp;quot;&#039; : &#039;&#039;;&lt;br /&gt;
   return &#039;&amp;lt;input disabled=&amp;quot;disabled&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;&#039;.$this-&amp;gt;inputname.&#039;&amp;quot; &#039;.$checked.&#039; /&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_default()====&lt;br /&gt;
Sets the default data for the field in the form object&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_default(&amp;amp;$mform) {&lt;br /&gt;
   if (!empty($default)) {&lt;br /&gt;
      $mform-&amp;gt;setDefault($this-&amp;gt;inputname, $this-&amp;gt;field-&amp;gt;defaultdata);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_validate_field()====&lt;br /&gt;
Validate the form field from profile page&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_validate_field($usernew) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   if (isset($usernew-&amp;gt;{$this-&amp;gt;inputname})) {&lt;br /&gt;
      if ($usernew-&amp;gt;{$this-&amp;gt;inputname}[&#039;text&#039;] === &#039;&#039;) {&lt;br /&gt;
       $errors[$this-&amp;gt;inputname] = &#039;error&#039;;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====edit_save_data_preprocess()====&lt;br /&gt;
Process the data before it gets saved in database&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_save_data_preprocess($data, &amp;amp;$datarecord) {&lt;br /&gt;
  if (is_array($data)) {&lt;br /&gt;
     $datarecord-&amp;gt;dataformat = $data[&#039;format&#039;];&lt;br /&gt;
     $data = $data[&#039;text&#039;];&lt;br /&gt;
  }&lt;br /&gt;
  return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_locked()====&lt;br /&gt;
HardFreeze the field if locked.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_locked(&amp;amp;$mform) {&lt;br /&gt;
   if (!$mform-&amp;gt;elementExists($this-&amp;gt;inputname)) {&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   if ($this-&amp;gt;is_locked() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
      $mform-&amp;gt;hardFreeze($this-&amp;gt;inputname);&lt;br /&gt;
      $mform-&amp;gt;setConstant($this-&amp;gt;inputname, $this-&amp;gt;data);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Common functions===&lt;br /&gt;
The following will need to be added to any files accessing the profile_ functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;dirroot/user/profile/lib.php&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====profile_user_record($userid)====&lt;br /&gt;
Returns an object with the custom profile fields set for the given user&lt;br /&gt;
====profile_save_data($usernew)====&lt;br /&gt;
Saves custom profile field data&lt;br /&gt;
====profile_validation($usernew, $files)====&lt;br /&gt;
Validates custom user profile field&lt;br /&gt;
&lt;br /&gt;
==Template==&lt;br /&gt;
[https://github.com/rajeshtaneja/userprofilefield user profile field template]&lt;br /&gt;
==Database tables==&lt;br /&gt;
Knowledge of database tables is not required for creating this plugin as, tables get populated when the fields are added to user profile page, by admin. There are two relevant tables for user profile fields:&lt;br /&gt;
# user_info_field - Information for custom field added to user profile page.&lt;br /&gt;
# user_info_data - Data added by user for the custom profile field&lt;br /&gt;
==FAQ==&lt;br /&gt;
===How to add custom user profile field===&lt;br /&gt;
Admin can add existing or custom profile fields. Refer [[:en : User profile fields]] for adding user profile fields to user profile.&lt;br /&gt;
===Which form elements does moodle support===&lt;br /&gt;
Refer [[Form_API]] for list of elements supported by moodle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58598</id>
		<title>User profile fields</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58598"/>
		<updated>2021-03-26T09:40:39Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* Naming convention */ Emphasised file names. Made the sentences easier to understand.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This plugin allows you to add custom user profile field types of which instances can be added to the user profile. For example, if you want to display radio buttons on the user profile, then create a radio user profile field plugin, then create an instance of it.&lt;br /&gt;
==History==&lt;br /&gt;
User profile fields exist from  Moodle 1.9 and support five default user profile field plugins:&lt;br /&gt;
# checkbox&lt;br /&gt;
# datetime&lt;br /&gt;
# menu&lt;br /&gt;
# text&lt;br /&gt;
# textarea&lt;br /&gt;
&lt;br /&gt;
==File Structure==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/user/profile/field/customprofilefieldplugin&#039;&#039;. The folder name should contain only letters and numbers.&lt;br /&gt;
# Create the following files and add them to customprofilefieldplugin:&lt;br /&gt;
## &#039;&#039;lang/en/profilefield_customprofilefieldplugin.php&#039;&#039; - Language file, containing strings for user profile field.&lt;br /&gt;
## &#039;&#039;define.class.php&#039;&#039; - Definition of the user profile field type will be added in this file.&lt;br /&gt;
## &#039;&#039;field.class.php&#039;&#039; - Controls user profile field display, while editing or showing as user profile field.&lt;br /&gt;
## &#039;&#039;version.php&#039;&#039; - Contains version information for customprofilefieldplugin.&lt;br /&gt;
&lt;br /&gt;
==Naming convention==&lt;br /&gt;
# &#039;&#039;&#039;profilefield_&#039;&#039;&#039; is prefixed to the name of the user profile field plugin, for identifying the name of the plugin.&lt;br /&gt;
# &#039;&#039;define.class.php&#039;&#039; should contain a class with a name that has &#039;&#039;&#039;profile_define_&#039;&#039;&#039; prefixed to the custom user profile field plugin name.&lt;br /&gt;
# &#039;&#039;field.class.php&#039;&#039; should contain a class with a name that has &#039;&#039;&#039;profile_field_&#039;&#039;&#039; prefixed to the custom user profile field plugin name.&lt;br /&gt;
# The language file should define a &#039;&#039;&#039;pluginname&#039;&#039;&#039; string as the name of the plugin.&lt;br /&gt;
&lt;br /&gt;
==Interface API==&lt;br /&gt;
===define.class.php===&lt;br /&gt;
====define_form_specific()====&lt;br /&gt;
Prints out the form snippet for the part of creating or editing a profile field specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_form_specific(&amp;amp;$form) {&lt;br /&gt;
   // select whether or not this should be checked by default&lt;br /&gt;
   $form-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;defaultdata&#039;, get_string(&#039;label&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   $form-&amp;gt;setDefault(&#039;defaultdata&#039;, 0); // defaults to &#039;no&#039;&lt;br /&gt;
   $form-&amp;gt;setType(&#039;defaultdata&#039;, PARAM_BOOL);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_validate_specific()====&lt;br /&gt;
Validate the data from the add/edit profile field form that is specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_validate_specific($data) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   // Make sure defaultdata is not false&lt;br /&gt;
   if ($data-&amp;gt;defaultdata == false) {&lt;br /&gt;
      $errors[&#039;defaultdata&#039;] = get_string(&#039;noprovided&#039;, &#039;profilefield_myprofilefield&#039;);&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_after_data====&lt;br /&gt;
Alter form based on submitted or existing data&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_after_data(&amp;amp;$form) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;shouldbeyes&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_save_preprocess====&lt;br /&gt;
Pre-process data from the profile field form before it is saved.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_save_preprocess($data) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $data-&amp;gt;defaultdata = NULL;&lt;br /&gt;
   }&lt;br /&gt;
   return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===field.class.php===&lt;br /&gt;
====edit_field_add()====&lt;br /&gt;
Adds the profile field to the moodle form&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_add(&amp;amp;$mform) {&lt;br /&gt;
   // Create form field&lt;br /&gt;
   $checkbox = &amp;amp;$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, $this-&amp;gt;inputname, format_string($this-&amp;gt;field-&amp;gt;name));&lt;br /&gt;
   if ($this-&amp;gt;data == &#039;1&#039;) {&lt;br /&gt;
       $checkbox-&amp;gt;setChecked(true);&lt;br /&gt;
   }&lt;br /&gt;
   $mform-&amp;gt;setType($this-&amp;gt;inputname, PARAM_BOOL);&lt;br /&gt;
   if ($this-&amp;gt;is_required() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
       $mform-&amp;gt;addRule($this-&amp;gt;inputname, get_string(&#039;required&#039;), &#039;nonzero&#039;, null, &#039;client&#039;);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====display_data()====&lt;br /&gt;
Display the data for this field&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function display_data() {&lt;br /&gt;
   $options = new stdClass();&lt;br /&gt;
   $options-&amp;gt;para = false;&lt;br /&gt;
   $checked = intval($this-&amp;gt;data) === 1 ? &#039;checked=&amp;quot;checked&amp;quot;&#039; : &#039;&#039;;&lt;br /&gt;
   return &#039;&amp;lt;input disabled=&amp;quot;disabled&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;&#039;.$this-&amp;gt;inputname.&#039;&amp;quot; &#039;.$checked.&#039; /&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_default()====&lt;br /&gt;
Sets the default data for the field in the form object&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_default(&amp;amp;$mform) {&lt;br /&gt;
   if (!empty($default)) {&lt;br /&gt;
      $mform-&amp;gt;setDefault($this-&amp;gt;inputname, $this-&amp;gt;field-&amp;gt;defaultdata);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_validate_field()====&lt;br /&gt;
Validate the form field from profile page&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_validate_field($usernew) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   if (isset($usernew-&amp;gt;{$this-&amp;gt;inputname})) {&lt;br /&gt;
      if ($usernew-&amp;gt;{$this-&amp;gt;inputname}[&#039;text&#039;] === &#039;&#039;) {&lt;br /&gt;
       $errors[$this-&amp;gt;inputname] = &#039;error&#039;;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====edit_save_data_preprocess()====&lt;br /&gt;
Process the data before it gets saved in database&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_save_data_preprocess($data, &amp;amp;$datarecord) {&lt;br /&gt;
  if (is_array($data)) {&lt;br /&gt;
     $datarecord-&amp;gt;dataformat = $data[&#039;format&#039;];&lt;br /&gt;
     $data = $data[&#039;text&#039;];&lt;br /&gt;
  }&lt;br /&gt;
  return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_locked()====&lt;br /&gt;
HardFreeze the field if locked.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_locked(&amp;amp;$mform) {&lt;br /&gt;
   if (!$mform-&amp;gt;elementExists($this-&amp;gt;inputname)) {&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   if ($this-&amp;gt;is_locked() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
      $mform-&amp;gt;hardFreeze($this-&amp;gt;inputname);&lt;br /&gt;
      $mform-&amp;gt;setConstant($this-&amp;gt;inputname, $this-&amp;gt;data);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Common functions===&lt;br /&gt;
The following will need to be added to any files accessing the profile_ functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;dirroot/user/profile/lib.php&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====profile_user_record($userid)====&lt;br /&gt;
Returns an object with the custom profile fields set for the given user&lt;br /&gt;
====profile_save_data($usernew)====&lt;br /&gt;
Saves custom profile field data&lt;br /&gt;
====profile_validation($usernew, $files)====&lt;br /&gt;
Validates custom user profile field&lt;br /&gt;
&lt;br /&gt;
==Template==&lt;br /&gt;
[https://github.com/rajeshtaneja/userprofilefield user profile field template]&lt;br /&gt;
==Database tables==&lt;br /&gt;
Knowledge of database tables is not required for creating this plugin as, tables get populated when the fields are added to user profile page, by admin. There are two relevant tables for user profile fields:&lt;br /&gt;
# user_info_field - Information for custom field added to user profile page.&lt;br /&gt;
# user_info_data - Data added by user for the custom profile field&lt;br /&gt;
==FAQ==&lt;br /&gt;
===How to add custom user profile field===&lt;br /&gt;
Admin can add existing or custom profile fields. Refer [[:en : User profile fields]] for adding user profile fields to user profile.&lt;br /&gt;
===Which form elements does moodle support===&lt;br /&gt;
Refer [[Form_API]] for list of elements supported by moodle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58597</id>
		<title>User profile fields</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58597"/>
		<updated>2021-03-26T09:35:04Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* File Structure */ Fixed grammar. Made capitalization consistent. Emphasized file names.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This plugin allows you to add custom user profile field types of which instances can be added to the user profile. For example, if you want to display radio buttons on the user profile, then create a radio user profile field plugin, then create an instance of it.&lt;br /&gt;
==History==&lt;br /&gt;
User profile fields exist from  Moodle 1.9 and support five default user profile field plugins:&lt;br /&gt;
# checkbox&lt;br /&gt;
# datetime&lt;br /&gt;
# menu&lt;br /&gt;
# text&lt;br /&gt;
# textarea&lt;br /&gt;
&lt;br /&gt;
==File Structure==&lt;br /&gt;
# Create a folder for your plugin in &#039;&#039;/user/profile/field/customprofilefieldplugin&#039;&#039;. The folder name should contain only letters and numbers.&lt;br /&gt;
# Create the following files and add them to customprofilefieldplugin:&lt;br /&gt;
## &#039;&#039;lang/en/profilefield_customprofilefieldplugin.php&#039;&#039; - Language file, containing strings for user profile field.&lt;br /&gt;
## &#039;&#039;define.class.php&#039;&#039; - Definition of the user profile field type will be added in this file.&lt;br /&gt;
## &#039;&#039;field.class.php&#039;&#039; - Controls user profile field display, while editing or showing as user profile field.&lt;br /&gt;
## &#039;&#039;version.php&#039;&#039; - Contains version information for customprofilefieldplugin.&lt;br /&gt;
&lt;br /&gt;
==Naming convention==&lt;br /&gt;
# &#039;&#039;&#039;profilefield_&#039;&#039;&#039; is prefixed to name of user profile field plugin, for identifying the name of the plugin.&lt;br /&gt;
# define.class.php should have a class with &#039;&#039;&#039;profile_define_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# field.class.php should have a class with &#039;&#039;&#039;profile_field_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# Language file should define &#039;&#039;&#039;pluginname&#039;&#039;&#039; as name of the plugin.&lt;br /&gt;
==Interface API==&lt;br /&gt;
===define.class.php===&lt;br /&gt;
====define_form_specific()====&lt;br /&gt;
Prints out the form snippet for the part of creating or editing a profile field specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_form_specific(&amp;amp;$form) {&lt;br /&gt;
   // select whether or not this should be checked by default&lt;br /&gt;
   $form-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;defaultdata&#039;, get_string(&#039;label&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   $form-&amp;gt;setDefault(&#039;defaultdata&#039;, 0); // defaults to &#039;no&#039;&lt;br /&gt;
   $form-&amp;gt;setType(&#039;defaultdata&#039;, PARAM_BOOL);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_validate_specific()====&lt;br /&gt;
Validate the data from the add/edit profile field form that is specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_validate_specific($data) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   // Make sure defaultdata is not false&lt;br /&gt;
   if ($data-&amp;gt;defaultdata == false) {&lt;br /&gt;
      $errors[&#039;defaultdata&#039;] = get_string(&#039;noprovided&#039;, &#039;profilefield_myprofilefield&#039;);&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_after_data====&lt;br /&gt;
Alter form based on submitted or existing data&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_after_data(&amp;amp;$form) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;shouldbeyes&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_save_preprocess====&lt;br /&gt;
Pre-process data from the profile field form before it is saved.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_save_preprocess($data) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $data-&amp;gt;defaultdata = NULL;&lt;br /&gt;
   }&lt;br /&gt;
   return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===field.class.php===&lt;br /&gt;
====edit_field_add()====&lt;br /&gt;
Adds the profile field to the moodle form&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_add(&amp;amp;$mform) {&lt;br /&gt;
   // Create form field&lt;br /&gt;
   $checkbox = &amp;amp;$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, $this-&amp;gt;inputname, format_string($this-&amp;gt;field-&amp;gt;name));&lt;br /&gt;
   if ($this-&amp;gt;data == &#039;1&#039;) {&lt;br /&gt;
       $checkbox-&amp;gt;setChecked(true);&lt;br /&gt;
   }&lt;br /&gt;
   $mform-&amp;gt;setType($this-&amp;gt;inputname, PARAM_BOOL);&lt;br /&gt;
   if ($this-&amp;gt;is_required() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
       $mform-&amp;gt;addRule($this-&amp;gt;inputname, get_string(&#039;required&#039;), &#039;nonzero&#039;, null, &#039;client&#039;);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====display_data()====&lt;br /&gt;
Display the data for this field&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function display_data() {&lt;br /&gt;
   $options = new stdClass();&lt;br /&gt;
   $options-&amp;gt;para = false;&lt;br /&gt;
   $checked = intval($this-&amp;gt;data) === 1 ? &#039;checked=&amp;quot;checked&amp;quot;&#039; : &#039;&#039;;&lt;br /&gt;
   return &#039;&amp;lt;input disabled=&amp;quot;disabled&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;&#039;.$this-&amp;gt;inputname.&#039;&amp;quot; &#039;.$checked.&#039; /&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_default()====&lt;br /&gt;
Sets the default data for the field in the form object&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_default(&amp;amp;$mform) {&lt;br /&gt;
   if (!empty($default)) {&lt;br /&gt;
      $mform-&amp;gt;setDefault($this-&amp;gt;inputname, $this-&amp;gt;field-&amp;gt;defaultdata);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_validate_field()====&lt;br /&gt;
Validate the form field from profile page&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_validate_field($usernew) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   if (isset($usernew-&amp;gt;{$this-&amp;gt;inputname})) {&lt;br /&gt;
      if ($usernew-&amp;gt;{$this-&amp;gt;inputname}[&#039;text&#039;] === &#039;&#039;) {&lt;br /&gt;
       $errors[$this-&amp;gt;inputname] = &#039;error&#039;;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====edit_save_data_preprocess()====&lt;br /&gt;
Process the data before it gets saved in database&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_save_data_preprocess($data, &amp;amp;$datarecord) {&lt;br /&gt;
  if (is_array($data)) {&lt;br /&gt;
     $datarecord-&amp;gt;dataformat = $data[&#039;format&#039;];&lt;br /&gt;
     $data = $data[&#039;text&#039;];&lt;br /&gt;
  }&lt;br /&gt;
  return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_locked()====&lt;br /&gt;
HardFreeze the field if locked.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_locked(&amp;amp;$mform) {&lt;br /&gt;
   if (!$mform-&amp;gt;elementExists($this-&amp;gt;inputname)) {&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   if ($this-&amp;gt;is_locked() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
      $mform-&amp;gt;hardFreeze($this-&amp;gt;inputname);&lt;br /&gt;
      $mform-&amp;gt;setConstant($this-&amp;gt;inputname, $this-&amp;gt;data);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Common functions===&lt;br /&gt;
The following will need to be added to any files accessing the profile_ functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;dirroot/user/profile/lib.php&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====profile_user_record($userid)====&lt;br /&gt;
Returns an object with the custom profile fields set for the given user&lt;br /&gt;
====profile_save_data($usernew)====&lt;br /&gt;
Saves custom profile field data&lt;br /&gt;
====profile_validation($usernew, $files)====&lt;br /&gt;
Validates custom user profile field&lt;br /&gt;
&lt;br /&gt;
==Template==&lt;br /&gt;
[https://github.com/rajeshtaneja/userprofilefield user profile field template]&lt;br /&gt;
==Database tables==&lt;br /&gt;
Knowledge of database tables is not required for creating this plugin as, tables get populated when the fields are added to user profile page, by admin. There are two relevant tables for user profile fields:&lt;br /&gt;
# user_info_field - Information for custom field added to user profile page.&lt;br /&gt;
# user_info_data - Data added by user for the custom profile field&lt;br /&gt;
==FAQ==&lt;br /&gt;
===How to add custom user profile field===&lt;br /&gt;
Admin can add existing or custom profile fields. Refer [[:en : User profile fields]] for adding user profile fields to user profile.&lt;br /&gt;
===Which form elements does moodle support===&lt;br /&gt;
Refer [[Form_API]] for list of elements supported by moodle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58596</id>
		<title>User profile fields</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58596"/>
		<updated>2021-03-26T09:30:01Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* File Structure */ Added missing full stop. Underscores in the folder name will be stripped out, but then the folder will not be found.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This plugin allows you to add custom user profile field types of which instances can be added to the user profile. For example, if you want to display radio buttons on the user profile, then create a radio user profile field plugin, then create an instance of it.&lt;br /&gt;
==History==&lt;br /&gt;
User profile fields exist from  Moodle 1.9 and support five default user profile field plugins:&lt;br /&gt;
# checkbox&lt;br /&gt;
# datetime&lt;br /&gt;
# menu&lt;br /&gt;
# text&lt;br /&gt;
# textarea&lt;br /&gt;
&lt;br /&gt;
==File Structure==&lt;br /&gt;
# Create a folder for your plugin in moodle/user/profile/field/customprofilefieldplugin. The folder name should contain only letters and numbers.&lt;br /&gt;
# Create following files and add them to customprofilefieldplugin&lt;br /&gt;
## lang/en/profilefield_customprofilefieldplugin.php - Language file, containing strings for user profile field.&lt;br /&gt;
## define.class.php - definition of user profile field will be added in this file.&lt;br /&gt;
## field.class.php - Controls user profile field display, while editing or showing as user profile field.&lt;br /&gt;
## version.php - contains version information for customprofilefieldplugin&lt;br /&gt;
&lt;br /&gt;
==Naming convention==&lt;br /&gt;
# &#039;&#039;&#039;profilefield_&#039;&#039;&#039; is prefixed to name of user profile field plugin, for identifying the name of the plugin.&lt;br /&gt;
# define.class.php should have a class with &#039;&#039;&#039;profile_define_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# field.class.php should have a class with &#039;&#039;&#039;profile_field_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# Language file should define &#039;&#039;&#039;pluginname&#039;&#039;&#039; as name of the plugin.&lt;br /&gt;
==Interface API==&lt;br /&gt;
===define.class.php===&lt;br /&gt;
====define_form_specific()====&lt;br /&gt;
Prints out the form snippet for the part of creating or editing a profile field specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_form_specific(&amp;amp;$form) {&lt;br /&gt;
   // select whether or not this should be checked by default&lt;br /&gt;
   $form-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;defaultdata&#039;, get_string(&#039;label&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   $form-&amp;gt;setDefault(&#039;defaultdata&#039;, 0); // defaults to &#039;no&#039;&lt;br /&gt;
   $form-&amp;gt;setType(&#039;defaultdata&#039;, PARAM_BOOL);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_validate_specific()====&lt;br /&gt;
Validate the data from the add/edit profile field form that is specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_validate_specific($data) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   // Make sure defaultdata is not false&lt;br /&gt;
   if ($data-&amp;gt;defaultdata == false) {&lt;br /&gt;
      $errors[&#039;defaultdata&#039;] = get_string(&#039;noprovided&#039;, &#039;profilefield_myprofilefield&#039;);&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_after_data====&lt;br /&gt;
Alter form based on submitted or existing data&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_after_data(&amp;amp;$form) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;shouldbeyes&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_save_preprocess====&lt;br /&gt;
Pre-process data from the profile field form before it is saved.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_save_preprocess($data) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $data-&amp;gt;defaultdata = NULL;&lt;br /&gt;
   }&lt;br /&gt;
   return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===field.class.php===&lt;br /&gt;
====edit_field_add()====&lt;br /&gt;
Adds the profile field to the moodle form&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_add(&amp;amp;$mform) {&lt;br /&gt;
   // Create form field&lt;br /&gt;
   $checkbox = &amp;amp;$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, $this-&amp;gt;inputname, format_string($this-&amp;gt;field-&amp;gt;name));&lt;br /&gt;
   if ($this-&amp;gt;data == &#039;1&#039;) {&lt;br /&gt;
       $checkbox-&amp;gt;setChecked(true);&lt;br /&gt;
   }&lt;br /&gt;
   $mform-&amp;gt;setType($this-&amp;gt;inputname, PARAM_BOOL);&lt;br /&gt;
   if ($this-&amp;gt;is_required() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
       $mform-&amp;gt;addRule($this-&amp;gt;inputname, get_string(&#039;required&#039;), &#039;nonzero&#039;, null, &#039;client&#039;);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====display_data()====&lt;br /&gt;
Display the data for this field&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function display_data() {&lt;br /&gt;
   $options = new stdClass();&lt;br /&gt;
   $options-&amp;gt;para = false;&lt;br /&gt;
   $checked = intval($this-&amp;gt;data) === 1 ? &#039;checked=&amp;quot;checked&amp;quot;&#039; : &#039;&#039;;&lt;br /&gt;
   return &#039;&amp;lt;input disabled=&amp;quot;disabled&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;&#039;.$this-&amp;gt;inputname.&#039;&amp;quot; &#039;.$checked.&#039; /&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_default()====&lt;br /&gt;
Sets the default data for the field in the form object&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_default(&amp;amp;$mform) {&lt;br /&gt;
   if (!empty($default)) {&lt;br /&gt;
      $mform-&amp;gt;setDefault($this-&amp;gt;inputname, $this-&amp;gt;field-&amp;gt;defaultdata);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_validate_field()====&lt;br /&gt;
Validate the form field from profile page&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_validate_field($usernew) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   if (isset($usernew-&amp;gt;{$this-&amp;gt;inputname})) {&lt;br /&gt;
      if ($usernew-&amp;gt;{$this-&amp;gt;inputname}[&#039;text&#039;] === &#039;&#039;) {&lt;br /&gt;
       $errors[$this-&amp;gt;inputname] = &#039;error&#039;;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====edit_save_data_preprocess()====&lt;br /&gt;
Process the data before it gets saved in database&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_save_data_preprocess($data, &amp;amp;$datarecord) {&lt;br /&gt;
  if (is_array($data)) {&lt;br /&gt;
     $datarecord-&amp;gt;dataformat = $data[&#039;format&#039;];&lt;br /&gt;
     $data = $data[&#039;text&#039;];&lt;br /&gt;
  }&lt;br /&gt;
  return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_locked()====&lt;br /&gt;
HardFreeze the field if locked.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_locked(&amp;amp;$mform) {&lt;br /&gt;
   if (!$mform-&amp;gt;elementExists($this-&amp;gt;inputname)) {&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   if ($this-&amp;gt;is_locked() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
      $mform-&amp;gt;hardFreeze($this-&amp;gt;inputname);&lt;br /&gt;
      $mform-&amp;gt;setConstant($this-&amp;gt;inputname, $this-&amp;gt;data);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Common functions===&lt;br /&gt;
The following will need to be added to any files accessing the profile_ functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;dirroot/user/profile/lib.php&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====profile_user_record($userid)====&lt;br /&gt;
Returns an object with the custom profile fields set for the given user&lt;br /&gt;
====profile_save_data($usernew)====&lt;br /&gt;
Saves custom profile field data&lt;br /&gt;
====profile_validation($usernew, $files)====&lt;br /&gt;
Validates custom user profile field&lt;br /&gt;
&lt;br /&gt;
==Template==&lt;br /&gt;
[https://github.com/rajeshtaneja/userprofilefield user profile field template]&lt;br /&gt;
==Database tables==&lt;br /&gt;
Knowledge of database tables is not required for creating this plugin as, tables get populated when the fields are added to user profile page, by admin. There are two relevant tables for user profile fields:&lt;br /&gt;
# user_info_field - Information for custom field added to user profile page.&lt;br /&gt;
# user_info_data - Data added by user for the custom profile field&lt;br /&gt;
==FAQ==&lt;br /&gt;
===How to add custom user profile field===&lt;br /&gt;
Admin can add existing or custom profile fields. Refer [[:en : User profile fields]] for adding user profile fields to user profile.&lt;br /&gt;
===Which form elements does moodle support===&lt;br /&gt;
Refer [[Form_API]] for list of elements supported by moodle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58595</id>
		<title>User profile fields</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58595"/>
		<updated>2021-03-26T09:27:38Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* History */ Fix grammar and make capitalization consistent in list of profile field plug-ins.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This plugin allows you to add custom user profile field types of which instances can be added to the user profile. For example, if you want to display radio buttons on the user profile, then create a radio user profile field plugin, then create an instance of it.&lt;br /&gt;
==History==&lt;br /&gt;
User profile fields exist from  Moodle 1.9 and support five default user profile field plugins:&lt;br /&gt;
# checkbox&lt;br /&gt;
# datetime&lt;br /&gt;
# menu&lt;br /&gt;
# text&lt;br /&gt;
# textarea&lt;br /&gt;
&lt;br /&gt;
==File Structure==&lt;br /&gt;
# Create a folder for your plugin in moodle/user/profile/field/customprofilefieldplugin&lt;br /&gt;
# Create following files and add them to customprofilefieldplugin&lt;br /&gt;
## lang/en/profilefield_customprofilefieldplugin.php - Language file, containing strings for user profile field.&lt;br /&gt;
## define.class.php - definition of user profile field will be added in this file.&lt;br /&gt;
## field.class.php - Controls user profile field display, while editing or showing as user profile field.&lt;br /&gt;
## version.php - contains version information for customprofilefieldplugin&lt;br /&gt;
==Naming convention==&lt;br /&gt;
# &#039;&#039;&#039;profilefield_&#039;&#039;&#039; is prefixed to name of user profile field plugin, for identifying the name of the plugin.&lt;br /&gt;
# define.class.php should have a class with &#039;&#039;&#039;profile_define_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# field.class.php should have a class with &#039;&#039;&#039;profile_field_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# Language file should define &#039;&#039;&#039;pluginname&#039;&#039;&#039; as name of the plugin.&lt;br /&gt;
==Interface API==&lt;br /&gt;
===define.class.php===&lt;br /&gt;
====define_form_specific()====&lt;br /&gt;
Prints out the form snippet for the part of creating or editing a profile field specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_form_specific(&amp;amp;$form) {&lt;br /&gt;
   // select whether or not this should be checked by default&lt;br /&gt;
   $form-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;defaultdata&#039;, get_string(&#039;label&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   $form-&amp;gt;setDefault(&#039;defaultdata&#039;, 0); // defaults to &#039;no&#039;&lt;br /&gt;
   $form-&amp;gt;setType(&#039;defaultdata&#039;, PARAM_BOOL);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_validate_specific()====&lt;br /&gt;
Validate the data from the add/edit profile field form that is specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_validate_specific($data) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   // Make sure defaultdata is not false&lt;br /&gt;
   if ($data-&amp;gt;defaultdata == false) {&lt;br /&gt;
      $errors[&#039;defaultdata&#039;] = get_string(&#039;noprovided&#039;, &#039;profilefield_myprofilefield&#039;);&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_after_data====&lt;br /&gt;
Alter form based on submitted or existing data&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_after_data(&amp;amp;$form) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;shouldbeyes&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_save_preprocess====&lt;br /&gt;
Pre-process data from the profile field form before it is saved.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_save_preprocess($data) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $data-&amp;gt;defaultdata = NULL;&lt;br /&gt;
   }&lt;br /&gt;
   return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===field.class.php===&lt;br /&gt;
====edit_field_add()====&lt;br /&gt;
Adds the profile field to the moodle form&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_add(&amp;amp;$mform) {&lt;br /&gt;
   // Create form field&lt;br /&gt;
   $checkbox = &amp;amp;$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, $this-&amp;gt;inputname, format_string($this-&amp;gt;field-&amp;gt;name));&lt;br /&gt;
   if ($this-&amp;gt;data == &#039;1&#039;) {&lt;br /&gt;
       $checkbox-&amp;gt;setChecked(true);&lt;br /&gt;
   }&lt;br /&gt;
   $mform-&amp;gt;setType($this-&amp;gt;inputname, PARAM_BOOL);&lt;br /&gt;
   if ($this-&amp;gt;is_required() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
       $mform-&amp;gt;addRule($this-&amp;gt;inputname, get_string(&#039;required&#039;), &#039;nonzero&#039;, null, &#039;client&#039;);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====display_data()====&lt;br /&gt;
Display the data for this field&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function display_data() {&lt;br /&gt;
   $options = new stdClass();&lt;br /&gt;
   $options-&amp;gt;para = false;&lt;br /&gt;
   $checked = intval($this-&amp;gt;data) === 1 ? &#039;checked=&amp;quot;checked&amp;quot;&#039; : &#039;&#039;;&lt;br /&gt;
   return &#039;&amp;lt;input disabled=&amp;quot;disabled&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;&#039;.$this-&amp;gt;inputname.&#039;&amp;quot; &#039;.$checked.&#039; /&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_default()====&lt;br /&gt;
Sets the default data for the field in the form object&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_default(&amp;amp;$mform) {&lt;br /&gt;
   if (!empty($default)) {&lt;br /&gt;
      $mform-&amp;gt;setDefault($this-&amp;gt;inputname, $this-&amp;gt;field-&amp;gt;defaultdata);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_validate_field()====&lt;br /&gt;
Validate the form field from profile page&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_validate_field($usernew) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   if (isset($usernew-&amp;gt;{$this-&amp;gt;inputname})) {&lt;br /&gt;
      if ($usernew-&amp;gt;{$this-&amp;gt;inputname}[&#039;text&#039;] === &#039;&#039;) {&lt;br /&gt;
       $errors[$this-&amp;gt;inputname] = &#039;error&#039;;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====edit_save_data_preprocess()====&lt;br /&gt;
Process the data before it gets saved in database&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_save_data_preprocess($data, &amp;amp;$datarecord) {&lt;br /&gt;
  if (is_array($data)) {&lt;br /&gt;
     $datarecord-&amp;gt;dataformat = $data[&#039;format&#039;];&lt;br /&gt;
     $data = $data[&#039;text&#039;];&lt;br /&gt;
  }&lt;br /&gt;
  return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_locked()====&lt;br /&gt;
HardFreeze the field if locked.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_locked(&amp;amp;$mform) {&lt;br /&gt;
   if (!$mform-&amp;gt;elementExists($this-&amp;gt;inputname)) {&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   if ($this-&amp;gt;is_locked() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
      $mform-&amp;gt;hardFreeze($this-&amp;gt;inputname);&lt;br /&gt;
      $mform-&amp;gt;setConstant($this-&amp;gt;inputname, $this-&amp;gt;data);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Common functions===&lt;br /&gt;
The following will need to be added to any files accessing the profile_ functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;dirroot/user/profile/lib.php&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====profile_user_record($userid)====&lt;br /&gt;
Returns an object with the custom profile fields set for the given user&lt;br /&gt;
====profile_save_data($usernew)====&lt;br /&gt;
Saves custom profile field data&lt;br /&gt;
====profile_validation($usernew, $files)====&lt;br /&gt;
Validates custom user profile field&lt;br /&gt;
&lt;br /&gt;
==Template==&lt;br /&gt;
[https://github.com/rajeshtaneja/userprofilefield user profile field template]&lt;br /&gt;
==Database tables==&lt;br /&gt;
Knowledge of database tables is not required for creating this plugin as, tables get populated when the fields are added to user profile page, by admin. There are two relevant tables for user profile fields:&lt;br /&gt;
# user_info_field - Information for custom field added to user profile page.&lt;br /&gt;
# user_info_data - Data added by user for the custom profile field&lt;br /&gt;
==FAQ==&lt;br /&gt;
===How to add custom user profile field===&lt;br /&gt;
Admin can add existing or custom profile fields. Refer [[:en : User profile fields]] for adding user profile fields to user profile.&lt;br /&gt;
===Which form elements does moodle support===&lt;br /&gt;
Refer [[Form_API]] for list of elements supported by moodle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58594</id>
		<title>User profile fields</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User_profile_fields&amp;diff=58594"/>
		<updated>2021-03-26T09:25:14Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: Improve grammar of introduction paragraph.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Introduction==&lt;br /&gt;
This plugin allows you to add custom user profile field types of which instances can be added to the user profile. For example, if you want to display radio buttons on the user profile, then create a radio user profile field plugin, then create an instance of it.&lt;br /&gt;
==History==&lt;br /&gt;
User profile fields exists from 1.9 and supports five default user profile field plugins:&lt;br /&gt;
# Checkbox&lt;br /&gt;
# datetime&lt;br /&gt;
# menu&lt;br /&gt;
# text&lt;br /&gt;
# textarea&lt;br /&gt;
==File Structure==&lt;br /&gt;
# Create a folder for your plugin in moodle/user/profile/field/customprofilefieldplugin&lt;br /&gt;
# Create following files and add them to customprofilefieldplugin&lt;br /&gt;
## lang/en/profilefield_customprofilefieldplugin.php - Language file, containing strings for user profile field.&lt;br /&gt;
## define.class.php - definition of user profile field will be added in this file.&lt;br /&gt;
## field.class.php - Controls user profile field display, while editing or showing as user profile field.&lt;br /&gt;
## version.php - contains version information for customprofilefieldplugin&lt;br /&gt;
==Naming convention==&lt;br /&gt;
# &#039;&#039;&#039;profilefield_&#039;&#039;&#039; is prefixed to name of user profile field plugin, for identifying the name of the plugin.&lt;br /&gt;
# define.class.php should have a class with &#039;&#039;&#039;profile_define_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# field.class.php should have a class with &#039;&#039;&#039;profile_field_&#039;&#039;&#039; prefix to custom user profile field plugin name.&lt;br /&gt;
# Language file should define &#039;&#039;&#039;pluginname&#039;&#039;&#039; as name of the plugin.&lt;br /&gt;
==Interface API==&lt;br /&gt;
===define.class.php===&lt;br /&gt;
====define_form_specific()====&lt;br /&gt;
Prints out the form snippet for the part of creating or editing a profile field specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_form_specific(&amp;amp;$form) {&lt;br /&gt;
   // select whether or not this should be checked by default&lt;br /&gt;
   $form-&amp;gt;addElement(&#039;selectyesno&#039;, &#039;defaultdata&#039;, get_string(&#039;label&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   $form-&amp;gt;setDefault(&#039;defaultdata&#039;, 0); // defaults to &#039;no&#039;&lt;br /&gt;
   $form-&amp;gt;setType(&#039;defaultdata&#039;, PARAM_BOOL);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_validate_specific()====&lt;br /&gt;
Validate the data from the add/edit profile field form that is specific to the current data type&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_validate_specific($data) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   // Make sure defaultdata is not false&lt;br /&gt;
   if ($data-&amp;gt;defaultdata == false) {&lt;br /&gt;
      $errors[&#039;defaultdata&#039;] = get_string(&#039;noprovided&#039;, &#039;profilefield_myprofilefield&#039;);&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_after_data====&lt;br /&gt;
Alter form based on submitted or existing data&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_after_data(&amp;amp;$form) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $mform-&amp;gt;addElement(&#039;static&#039;, &#039;description&#039;, get_string(&#039;shouldbeyes&#039;, &#039;profilefield_myprofilefield&#039;));&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====define_save_preprocess====&lt;br /&gt;
Pre-process data from the profile field form before it is saved.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function define_save_preprocess($data) {&lt;br /&gt;
   if (empty($data-&amp;gt;defaultdata)) {&lt;br /&gt;
      $data-&amp;gt;defaultdata = NULL;&lt;br /&gt;
   }&lt;br /&gt;
   return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===field.class.php===&lt;br /&gt;
====edit_field_add()====&lt;br /&gt;
Adds the profile field to the moodle form&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_add(&amp;amp;$mform) {&lt;br /&gt;
   // Create form field&lt;br /&gt;
   $checkbox = &amp;amp;$mform-&amp;gt;addElement(&#039;advcheckbox&#039;, $this-&amp;gt;inputname, format_string($this-&amp;gt;field-&amp;gt;name));&lt;br /&gt;
   if ($this-&amp;gt;data == &#039;1&#039;) {&lt;br /&gt;
       $checkbox-&amp;gt;setChecked(true);&lt;br /&gt;
   }&lt;br /&gt;
   $mform-&amp;gt;setType($this-&amp;gt;inputname, PARAM_BOOL);&lt;br /&gt;
   if ($this-&amp;gt;is_required() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
       $mform-&amp;gt;addRule($this-&amp;gt;inputname, get_string(&#039;required&#039;), &#039;nonzero&#039;, null, &#039;client&#039;);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====display_data()====&lt;br /&gt;
Display the data for this field&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function display_data() {&lt;br /&gt;
   $options = new stdClass();&lt;br /&gt;
   $options-&amp;gt;para = false;&lt;br /&gt;
   $checked = intval($this-&amp;gt;data) === 1 ? &#039;checked=&amp;quot;checked&amp;quot;&#039; : &#039;&#039;;&lt;br /&gt;
   return &#039;&amp;lt;input disabled=&amp;quot;disabled&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;&#039;.$this-&amp;gt;inputname.&#039;&amp;quot; &#039;.$checked.&#039; /&amp;gt;&#039;;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_default()====&lt;br /&gt;
Sets the default data for the field in the form object&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_default(&amp;amp;$mform) {&lt;br /&gt;
   if (!empty($default)) {&lt;br /&gt;
      $mform-&amp;gt;setDefault($this-&amp;gt;inputname, $this-&amp;gt;field-&amp;gt;defaultdata);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_validate_field()====&lt;br /&gt;
Validate the form field from profile page&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_validate_field($usernew) {&lt;br /&gt;
   $errors = array();&lt;br /&gt;
   if (isset($usernew-&amp;gt;{$this-&amp;gt;inputname})) {&lt;br /&gt;
      if ($usernew-&amp;gt;{$this-&amp;gt;inputname}[&#039;text&#039;] === &#039;&#039;) {&lt;br /&gt;
       $errors[$this-&amp;gt;inputname] = &#039;error&#039;;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
   return $errors;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====edit_save_data_preprocess()====&lt;br /&gt;
Process the data before it gets saved in database&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_save_data_preprocess($data, &amp;amp;$datarecord) {&lt;br /&gt;
  if (is_array($data)) {&lt;br /&gt;
     $datarecord-&amp;gt;dataformat = $data[&#039;format&#039;];&lt;br /&gt;
     $data = $data[&#039;text&#039;];&lt;br /&gt;
  }&lt;br /&gt;
  return $data;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====edit_field_set_locked()====&lt;br /&gt;
HardFreeze the field if locked.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
function edit_field_set_locked(&amp;amp;$mform) {&lt;br /&gt;
   if (!$mform-&amp;gt;elementExists($this-&amp;gt;inputname)) {&lt;br /&gt;
      return;&lt;br /&gt;
   }&lt;br /&gt;
   if ($this-&amp;gt;is_locked() and !has_capability(&#039;moodle/user:update&#039;, get_context_instance(CONTEXT_SYSTEM))) {&lt;br /&gt;
      $mform-&amp;gt;hardFreeze($this-&amp;gt;inputname);&lt;br /&gt;
      $mform-&amp;gt;setConstant($this-&amp;gt;inputname, $this-&amp;gt;data);&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
===Common functions===&lt;br /&gt;
The following will need to be added to any files accessing the profile_ functions:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
require_once(&amp;quot;$CFG-&amp;gt;dirroot/user/profile/lib.php&amp;quot;);&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
====profile_user_record($userid)====&lt;br /&gt;
Returns an object with the custom profile fields set for the given user&lt;br /&gt;
====profile_save_data($usernew)====&lt;br /&gt;
Saves custom profile field data&lt;br /&gt;
====profile_validation($usernew, $files)====&lt;br /&gt;
Validates custom user profile field&lt;br /&gt;
&lt;br /&gt;
==Template==&lt;br /&gt;
[https://github.com/rajeshtaneja/userprofilefield user profile field template]&lt;br /&gt;
==Database tables==&lt;br /&gt;
Knowledge of database tables is not required for creating this plugin as, tables get populated when the fields are added to user profile page, by admin. There are two relevant tables for user profile fields:&lt;br /&gt;
# user_info_field - Information for custom field added to user profile page.&lt;br /&gt;
# user_info_data - Data added by user for the custom profile field&lt;br /&gt;
==FAQ==&lt;br /&gt;
===How to add custom user profile field===&lt;br /&gt;
Admin can add existing or custom profile fields. Refer [[:en : User profile fields]] for adding user profile fields to user profile.&lt;br /&gt;
===Which form elements does moodle support===&lt;br /&gt;
Refer [[Form_API]] for list of elements supported by moodle&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Extending_the_theme_custom_menu&amp;diff=57727</id>
		<title>Extending the theme custom menu</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Extending_the_theme_custom_menu&amp;diff=57727"/>
		<updated>2020-07-22T08:32:52Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* Before we begin */ Punctuation&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Themes}}This is a quick tutorial that will run you through extending the custom menu by overriding your theme&#039;s renderer.&lt;br /&gt;
&lt;br /&gt;
This tutorial is primarily PHP coding, and ranges from moderate to advanced difficulty.&lt;br /&gt;
&lt;br /&gt;
==Before we begin==&lt;br /&gt;
First things first, you need to know a little something about the custom menu. The custom menu is populated from the manually entered input in &#039;&#039;&amp;quot;Theme Settings&amp;quot;&#039;&#039;. Once the administrator has entered the custom menu items and saved them, the following steps are what they go through in order to be displayed:&lt;br /&gt;
# The theme calls &#039;&#039;&#039;&#039;&#039;$OUTPUT-&amp;gt;custom_menu()&#039;&#039;&#039;&#039;&#039; which is the core_renderer&#039;s method responsible for producing the custom menu.&lt;br /&gt;
# core_renderer::custom_menu() does the following:&lt;br /&gt;
## Checks to make sure the admin has added custom menu items.&lt;br /&gt;
## Creates a new &#039;&#039;&#039;&#039;&#039;custom_menu&#039;&#039;&#039;&#039;&#039; object. When the custom menu object is created, it turns whatever the admin entered, into a structured array of information.&lt;br /&gt;
## Calls core_renderer::render_custom_menu and gives it the custom_menu object.&lt;br /&gt;
# core_renderer::render_custom_menu is where the magic happens. It does the following:&lt;br /&gt;
## First, it checks to make sure custom_menu contains items.&lt;br /&gt;
## Initializes the JavaScript for the custom menu. This is the YUI3 menunode component.&lt;br /&gt;
## Creates the HTML base of the custom menu.&lt;br /&gt;
## Then iterates through all of the items and calls the custom menu and passes them to another function that will turn them into HTML correctly.&lt;br /&gt;
&lt;br /&gt;
I&#039;m going to stop there, as there is no need at this point to go into any more detail. Don&#039;t worry if you are a little lost, it will get clearer as we start working through code.&lt;br /&gt;
&lt;br /&gt;
In this tutorial will we look at how to extend the theme&#039;s renderer in two different way.&lt;br /&gt;
# Add a dynamic My Courses branch to the custom menu that will display all of the courses a user is enrolled in.&lt;br /&gt;
# Get the custom menu to fetch strings from the language files rather than just static strings you type, allowing for a translatable custom menu.&lt;br /&gt;
&lt;br /&gt;
Before you start into this tutorial you should have read the following tutorial, or at least have a good knowledge of the the Moodle theme engine and Moodle development.&lt;br /&gt;
* [[Creating a theme based on boost]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
As this is a quick tutorial I am going to assume you have created a theme, tested it and got it all working, and are already well on your way to becoming a theme guru.&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
Alright, as you have already have your theme ready to go preparation is pretty simple, we are going to go through and create (if you haven&#039;t already) the following files:&lt;br /&gt;
* theme/themename/lib.php&lt;br /&gt;
* theme/themename/renderers.php&lt;br /&gt;
* theme/themename/lang/en/themename.php&lt;br /&gt;
&lt;br /&gt;
Next step open up your themes config.php file and add the following configuration option to it (at the bottom):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;rendererfactory = &#039;theme_overridden_renderer_factory&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve already got a custom renderer you will already have this line.&lt;br /&gt;
&lt;br /&gt;
And thats it! now we move on to extending the custom menu.&lt;br /&gt;
&lt;br /&gt;
==Adding the My Courses branch==&lt;br /&gt;
So the point of this extension is to add a &#039;&#039;&#039;My Courses&#039;&#039;&#039; branch to the end of the custom menu.&lt;br /&gt;
&lt;br /&gt;
The plan is to have the my courses branch and then within that branch have an entry for every course the user is enrolled in, much the same as the my courses branch of the navigation. &lt;br /&gt;
&lt;br /&gt;
In order to achieve this we need to add some items to the custom menu, the my courses branch and all of the courses within it. We can do this overriding the core_renderers &#039;&#039;&#039;render_custom_menu&#039;&#039;&#039; method, of more accuratly create our own render_custom_menu method that adds our items and then calls the original. Remember we only need to add items, we don&#039;t need to change what is being produced.&lt;br /&gt;
&lt;br /&gt;
So within our renderers.php file add the following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class theme_themename_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu(custom_menu $menu) {&lt;br /&gt;
        // Our code will go here shortly&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So that is pretty simple right?!&lt;br /&gt;
&lt;br /&gt;
Here we are defining our core_renderer which will contain our overridden method &#039;&#039;render_custom_menu&#039;&#039; which we have also defined there.&lt;br /&gt;
Note the definition of the render_custom_menu must be the same as the original, this means it must be &#039;&#039;&#039;protected&#039;&#039;&#039; and it must take one argument &#039;&#039;&#039;custom_menu $menu&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Next step is to write the code for our render_custom_menu method. As stated above we want to add a branch and courses to the end of it which we can do with the following bit of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&lt;br /&gt;
if (isloggedin() &amp;amp;&amp;amp; $mycourses &amp;amp;&amp;amp; $mycourses-&amp;gt;has_children()) {&lt;br /&gt;
    $branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
    $branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
    $branchtitle = $branchlabel;&lt;br /&gt;
    $branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
    $branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&lt;br /&gt;
    foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
        $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
return parent::render_custom_menu($menu);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So how this all works....&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This line is a little bit of smarts, what we are doing is getting the mycourses branch from the navigation. We could make all of the database calls and work it all out ourselves but this will be much better for performance and is easier!&lt;br /&gt;
&lt;br /&gt;
The next line of code is an &#039;&#039;if&#039;&#039; statement that checks three things&lt;br /&gt;
# The user is logged in, you must be logged in to see your courses.&lt;br /&gt;
# That we have a mycourses object, if the user isn&#039;t enrolled in anything they won&#039;t have a mycourses object.&lt;br /&gt;
# The the mycourses object has children, if it exists it should but it is better to be safe than get errors.&lt;br /&gt;
&lt;br /&gt;
Within the if statement we are doing two main things happening, the first is to add the branch to the menu:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
$branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
$branchtitle = $branchlabel;&lt;br /&gt;
$branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
$branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
When adding a new branch we need to give it three things:&lt;br /&gt;
# A label &#039;&#039;&#039;$branchlabel&#039;&#039;&#039;.&lt;br /&gt;
# A URL &#039;&#039;&#039;$branchurl&#039;&#039;&#039;.&lt;br /&gt;
# A title &#039;&#039;&#039;$branchtitle&#039;&#039;&#039; in this case I have just set it to the same as $branchlabel because I am lazy, you can make it anything you want.&lt;br /&gt;
# A sort order &#039;&#039;&#039;$branchsort&#039;&#039;&#039; this just needs to be high enough that it ends up on last place where we want it. Make it small to put it at the front.&lt;br /&gt;
&lt;br /&gt;
The final line of code from above simply adds it to the menu and collects a reference to it so that we can add courses to it.&lt;br /&gt;
&lt;br /&gt;
The second thing being done in the if statement is iterate through all of the courses in the mycourses object and add them to the branch. That is done with the following bit of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
    $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
So here we go through all of the mycourses objects children (which we know will be courses) and for each one we add an item to the branch.&lt;br /&gt;
When adding items here, like above, we need to give it the following:&lt;br /&gt;
# A label &#039;&#039;&#039;$coursenode-&amp;gt;get_content()&#039;&#039;&#039; returns us the text in the navigation node.&lt;br /&gt;
# A url &#039;&#039;&#039;$coursenode-&amp;gt;action&#039;&#039;&#039; which is the URL for the node.&lt;br /&gt;
# A title &#039;&#039;&#039;$coursenode-&amp;gt;get_title()&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
In this case we don&#039;t need to set a sort order because the navigation has already ordered them correctly!&lt;br /&gt;
&lt;br /&gt;
So now we are through the if statement and there is only one line of code left:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
return parent::render_custom_menu($menu);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line of code simply calls the original &#039;&#039;&#039;core_renderer::render_custom_menu&#039;&#039;&#039; method to do all of the remaining work. Because we don&#039;t need to change the display at all we don&#039;t need to redo what it does, we can just use it!.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
How easy way that?! it&#039;s all done, if you open you site in your browser and log in the custom menu should now contain a my courses branch (providing you are enrolled in courses).&lt;br /&gt;
&lt;br /&gt;
==Loading labels from language files==&lt;br /&gt;
If you run a site that is available in more than one language &#039;&#039;&#039;and&#039;&#039;&#039; you want to make use of the custom menu then you will probably be very interested in this.&lt;br /&gt;
&lt;br /&gt;
The idea behind this extension is to load the labels and titles that get shown in the custom menu from the theme&#039;s language files rather than having just the fixed strings you type into the admin setting.&lt;br /&gt;
&lt;br /&gt;
In order to achieve this we need to do somehow override the custom_menu_item class so that it loads the strings from the database if they match a special pattern. We can then update the admin setting to use our patter and wallah! things should load from the language files.&lt;br /&gt;
&lt;br /&gt;
What makes this tricky is that we can&#039;t just override the custom_menu_item class, we also need to override the thing that makes create custom_menu_item instances which in this case is the core_renderer::render_custom_menu_item method.&lt;br /&gt;
&lt;br /&gt;
===Overriding the custom_menu_item class===&lt;br /&gt;
Within your themes lib.php file add the following lines of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class theme_themename_transmuted_custom_menu_item extends custom_menu_item {&lt;br /&gt;
    public function __construct(custom_menu_item $menunode) {&lt;br /&gt;
        // Our code will go here&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
What we have done here is create an overridden custom_menu_item class called &#039;&#039;&#039;transmuted_custom_menu_item&#039;&#039;&#039;.&lt;br /&gt;
Within that class we are overriding the constructor, the constructor will be given the original menu item, and we will need to instantiate this object with the properties of the original. Once we have instantiated it, with the properties of the original, we can alter then as we like.&lt;br /&gt;
&lt;br /&gt;
Next we need to write the contents of the &#039;&#039;__construct&#039;&#039; method:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
$this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;text = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;title, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;title = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;title = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So there are essentially four things going on here.&lt;br /&gt;
&lt;br /&gt;
First we need to populate this object with the properties of the original item. We do this by calling the original constructor with $menunode properties as shown below.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next we need to copy the properties that are not included in the original constructor, in this case there is only one &#039;&#039;&#039;$this-&amp;gt;children&#039;&#039;&#039;. This should be an array of all of this item&#039;s children (sub items).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the properties set up we can modify them. In our case we want to check if the items label and title match a special pattern and if they do we want to fetch them from the language file instead.&lt;br /&gt;
The special pattern is &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[stringname]]&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; where stringname is the name of the string that we want to get from the language file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;text = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In the code above we do the following:&lt;br /&gt;
# Create an array $matches which will hold the stringname if the label matches the pattern.&lt;br /&gt;
# We attempt to match the label to the pattern. If it does the $matches array now contains the stringname.&lt;br /&gt;
# If it did match we call get string as shown.&lt;br /&gt;
&lt;br /&gt;
The third and final thing is to do the above again but this time for the title.&lt;br /&gt;
&lt;br /&gt;
With that done our transmutable_custom_menu_item class is complete. Next step is to make use of it.&lt;br /&gt;
&lt;br /&gt;
===Overriding render_custom_menu_item===&lt;br /&gt;
The next step is make use of the transmutable_custom_menu_item class we created previously. &lt;br /&gt;
&lt;br /&gt;
We can do this by overriding the &#039;&#039;&#039;core_renderer::render_custom_menu_item&#039;&#039;&#039; method within our renderers.php file as shown below.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function render_custom_menu_item(custom_menu_item $menunode) {&lt;br /&gt;
    $transmutedmenunode = new theme_themename_transmuted_custom_menu_item($menunode);&lt;br /&gt;
    return parent::render_custom_menu_item($transmutedmenunode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This is pretty simply, essentially we are using our transmuted_custom_menu_item class like a façade to the original custom_menu_item class by creating a new transmuted instance using the original.&lt;br /&gt;
Once we have the transmuted object we can call the original render_custom_menu_item method with it.&lt;br /&gt;
&lt;br /&gt;
And that is it! Congratulations if you got it this far.&lt;br /&gt;
&lt;br /&gt;
The only thing left to do is add strings to your themes language file as required!&lt;br /&gt;
&lt;br /&gt;
==Complete source==&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// theme/themename/renderers.php&lt;br /&gt;
&lt;br /&gt;
class theme_themename_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu(custom_menu $menu) {&lt;br /&gt;
        &lt;br /&gt;
        $mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (isloggedin() &amp;amp;&amp;amp; $mycourses &amp;amp;&amp;amp; $mycourses-&amp;gt;has_children()) {&lt;br /&gt;
            $branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
            $branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
            $branchtitle = $branchlabel;&lt;br /&gt;
            $branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
            $branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&lt;br /&gt;
            foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
                $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parent::render_custom_menu($menu);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu_item(custom_menu_item $menunode) {&lt;br /&gt;
        $transmutedmenunode = new theme_themename_transmuted_custom_menu_item($menunode);&lt;br /&gt;
        return parent::render_custom_menu_item($transmutedmenunode);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// theme/themename/lib.php&lt;br /&gt;
&lt;br /&gt;
class theme_themename_transmuted_custom_menu_item extends custom_menu_item {&lt;br /&gt;
    public function __construct(custom_menu_item $menunode) {&lt;br /&gt;
        parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
        $this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&lt;br /&gt;
        $matches = array();&lt;br /&gt;
        if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
            try {&lt;br /&gt;
                $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
            } catch (Exception $e) {&lt;br /&gt;
                $this-&amp;gt;text = $matches[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $matches = array();&lt;br /&gt;
        if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;title, $matches)) {&lt;br /&gt;
            try {&lt;br /&gt;
                $this-&amp;gt;title = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
            } catch (Exception $e) {&lt;br /&gt;
                $this-&amp;gt;title = $matches[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Adding courses and categories to the custom menu]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Extending_the_theme_custom_menu&amp;diff=57726</id>
		<title>Extending the theme custom menu</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Extending_the_theme_custom_menu&amp;diff=57726"/>
		<updated>2020-07-22T08:17:05Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: /* Before we begin */ Add appropriate commas.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Themes}}This is a quick tutorial that will run you through extending the custom menu by overriding your theme&#039;s renderer.&lt;br /&gt;
&lt;br /&gt;
This tutorial is primarily PHP coding, and ranges from moderate to advanced difficulty.&lt;br /&gt;
&lt;br /&gt;
==Before we begin==&lt;br /&gt;
First things first, you need to know a little something about the custom menu. The custom menu is populated from the manually entered input in &#039;&#039;&amp;quot;Theme Settings&amp;quot;&#039;&#039;. Once the administrator has entered the custom menu items and saved them, the following steps are what they go through in order to be displayed:&lt;br /&gt;
# The theme calls &#039;&#039;&#039;&#039;&#039;$OUTPUT-&amp;gt;custom_menu()&#039;&#039;&#039;&#039;&#039; which is the core_renderers method responsible for producing the custom menu.&lt;br /&gt;
# core_renderer::custom_menu() does the following:&lt;br /&gt;
## Checks to make sure the admin has added custom menu items.&lt;br /&gt;
## Creates a new &#039;&#039;&#039;&#039;&#039;custom_menu&#039;&#039;&#039;&#039;&#039; object. When the custom menu object is created it turns what ever the admin entered into a structured array of information.&lt;br /&gt;
## Calls core_renderer::render_custom_menu and gives it the custom_menu object.&lt;br /&gt;
# core_renderer::render_custom_menu is where the magic happens, it does the following.&lt;br /&gt;
## First it checks to make sure custom menu contains items.&lt;br /&gt;
## Initialises the JavaScript for the custom menu, this is the YUI3 menunode component.&lt;br /&gt;
## Creates the HTML base of the custom menu&lt;br /&gt;
## Then iterates through all of the items and calls the custom menu and passes them to another function that will turn them into HTML correctly.&lt;br /&gt;
&lt;br /&gt;
I&#039;m going to stop there, as there is no need at this point to go into any more detail. Don&#039;t worry if you are a little lost, it will get clearer as we start working through code.&lt;br /&gt;
&lt;br /&gt;
In this tutorial will we look at how to extend the theme&#039;s renderer in two different way.&lt;br /&gt;
# Add a dynamic My Courses branch to the custom menu that will display all of the courses a user is enrolled in.&lt;br /&gt;
# Get the custom menu to fetch strings from the language files rather than just static strings you type, allowing for a translatable custom menu.&lt;br /&gt;
&lt;br /&gt;
Before you start into this tutorial you should have read the following tutorial, or at least have a good knowledge of the the Moodle theme engine and Moodle development.&lt;br /&gt;
* [[Creating a theme based on boost]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
As this is a quick tutorial I am going to assume you have created a theme, tested it and got it all working, and are already well on your way to becoming a theme guru.&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
Alright, as you have already have your theme ready to go preparation is pretty simple, we are going to go through and create (if you haven&#039;t already) the following files:&lt;br /&gt;
* theme/themename/lib.php&lt;br /&gt;
* theme/themename/renderers.php&lt;br /&gt;
* theme/themename/lang/en/themename.php&lt;br /&gt;
&lt;br /&gt;
Next step open up your themes config.php file and add the following configuration option to it (at the bottom):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;rendererfactory = &#039;theme_overridden_renderer_factory&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve already got a custom renderer you will already have this line.&lt;br /&gt;
&lt;br /&gt;
And thats it! now we move on to extending the custom menu.&lt;br /&gt;
&lt;br /&gt;
==Adding the My Courses branch==&lt;br /&gt;
So the point of this extension is to add a &#039;&#039;&#039;My Courses&#039;&#039;&#039; branch to the end of the custom menu.&lt;br /&gt;
&lt;br /&gt;
The plan is to have the my courses branch and then within that branch have an entry for every course the user is enrolled in, much the same as the my courses branch of the navigation. &lt;br /&gt;
&lt;br /&gt;
In order to achieve this we need to add some items to the custom menu, the my courses branch and all of the courses within it. We can do this overriding the core_renderers &#039;&#039;&#039;render_custom_menu&#039;&#039;&#039; method, of more accuratly create our own render_custom_menu method that adds our items and then calls the original. Remember we only need to add items, we don&#039;t need to change what is being produced.&lt;br /&gt;
&lt;br /&gt;
So within our renderers.php file add the following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class theme_themename_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu(custom_menu $menu) {&lt;br /&gt;
        // Our code will go here shortly&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So that is pretty simple right?!&lt;br /&gt;
&lt;br /&gt;
Here we are defining our core_renderer which will contain our overridden method &#039;&#039;render_custom_menu&#039;&#039; which we have also defined there.&lt;br /&gt;
Note the definition of the render_custom_menu must be the same as the original, this means it must be &#039;&#039;&#039;protected&#039;&#039;&#039; and it must take one argument &#039;&#039;&#039;custom_menu $menu&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Next step is to write the code for our render_custom_menu method. As stated above we want to add a branch and courses to the end of it which we can do with the following bit of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&lt;br /&gt;
if (isloggedin() &amp;amp;&amp;amp; $mycourses &amp;amp;&amp;amp; $mycourses-&amp;gt;has_children()) {&lt;br /&gt;
    $branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
    $branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
    $branchtitle = $branchlabel;&lt;br /&gt;
    $branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
    $branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&lt;br /&gt;
    foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
        $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
return parent::render_custom_menu($menu);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So how this all works....&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This line is a little bit of smarts, what we are doing is getting the mycourses branch from the navigation. We could make all of the database calls and work it all out ourselves but this will be much better for performance and is easier!&lt;br /&gt;
&lt;br /&gt;
The next line of code is an &#039;&#039;if&#039;&#039; statement that checks three things&lt;br /&gt;
# The user is logged in, you must be logged in to see your courses.&lt;br /&gt;
# That we have a mycourses object, if the user isn&#039;t enrolled in anything they won&#039;t have a mycourses object.&lt;br /&gt;
# The the mycourses object has children, if it exists it should but it is better to be safe than get errors.&lt;br /&gt;
&lt;br /&gt;
Within the if statement we are doing two main things happening, the first is to add the branch to the menu:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
$branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
$branchtitle = $branchlabel;&lt;br /&gt;
$branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
$branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
When adding a new branch we need to give it three things:&lt;br /&gt;
# A label &#039;&#039;&#039;$branchlabel&#039;&#039;&#039;.&lt;br /&gt;
# A URL &#039;&#039;&#039;$branchurl&#039;&#039;&#039;.&lt;br /&gt;
# A title &#039;&#039;&#039;$branchtitle&#039;&#039;&#039; in this case I have just set it to the same as $branchlabel because I am lazy, you can make it anything you want.&lt;br /&gt;
# A sort order &#039;&#039;&#039;$branchsort&#039;&#039;&#039; this just needs to be high enough that it ends up on last place where we want it. Make it small to put it at the front.&lt;br /&gt;
&lt;br /&gt;
The final line of code from above simply adds it to the menu and collects a reference to it so that we can add courses to it.&lt;br /&gt;
&lt;br /&gt;
The second thing being done in the if statement is iterate through all of the courses in the mycourses object and add them to the branch. That is done with the following bit of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
    $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
So here we go through all of the mycourses objects children (which we know will be courses) and for each one we add an item to the branch.&lt;br /&gt;
When adding items here, like above, we need to give it the following:&lt;br /&gt;
# A label &#039;&#039;&#039;$coursenode-&amp;gt;get_content()&#039;&#039;&#039; returns us the text in the navigation node.&lt;br /&gt;
# A url &#039;&#039;&#039;$coursenode-&amp;gt;action&#039;&#039;&#039; which is the URL for the node.&lt;br /&gt;
# A title &#039;&#039;&#039;$coursenode-&amp;gt;get_title()&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
In this case we don&#039;t need to set a sort order because the navigation has already ordered them correctly!&lt;br /&gt;
&lt;br /&gt;
So now we are through the if statement and there is only one line of code left:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
return parent::render_custom_menu($menu);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line of code simply calls the original &#039;&#039;&#039;core_renderer::render_custom_menu&#039;&#039;&#039; method to do all of the remaining work. Because we don&#039;t need to change the display at all we don&#039;t need to redo what it does, we can just use it!.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
How easy way that?! it&#039;s all done, if you open you site in your browser and log in the custom menu should now contain a my courses branch (providing you are enrolled in courses).&lt;br /&gt;
&lt;br /&gt;
==Loading labels from language files==&lt;br /&gt;
If you run a site that is available in more than one language &#039;&#039;&#039;and&#039;&#039;&#039; you want to make use of the custom menu then you will probably be very interested in this.&lt;br /&gt;
&lt;br /&gt;
The idea behind this extension is to load the labels and titles that get shown in the custom menu from the theme&#039;s language files rather than having just the fixed strings you type into the admin setting.&lt;br /&gt;
&lt;br /&gt;
In order to achieve this we need to do somehow override the custom_menu_item class so that it loads the strings from the database if they match a special pattern. We can then update the admin setting to use our patter and wallah! things should load from the language files.&lt;br /&gt;
&lt;br /&gt;
What makes this tricky is that we can&#039;t just override the custom_menu_item class, we also need to override the thing that makes create custom_menu_item instances which in this case is the core_renderer::render_custom_menu_item method.&lt;br /&gt;
&lt;br /&gt;
===Overriding the custom_menu_item class===&lt;br /&gt;
Within your themes lib.php file add the following lines of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class theme_themename_transmuted_custom_menu_item extends custom_menu_item {&lt;br /&gt;
    public function __construct(custom_menu_item $menunode) {&lt;br /&gt;
        // Our code will go here&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
What we have done here is create an overridden custom_menu_item class called &#039;&#039;&#039;transmuted_custom_menu_item&#039;&#039;&#039;.&lt;br /&gt;
Within that class we are overriding the constructor, the constructor will be given the original menu item, and we will need to instantiate this object with the properties of the original. Once we have instantiated it, with the properties of the original, we can alter then as we like.&lt;br /&gt;
&lt;br /&gt;
Next we need to write the contents of the &#039;&#039;__construct&#039;&#039; method:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
$this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;text = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;title, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;title = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;title = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So there are essentially four things going on here.&lt;br /&gt;
&lt;br /&gt;
First we need to populate this object with the properties of the original item. We do this by calling the original constructor with $menunode properties as shown below.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next we need to copy the properties that are not included in the original constructor, in this case there is only one &#039;&#039;&#039;$this-&amp;gt;children&#039;&#039;&#039;. This should be an array of all of this item&#039;s children (sub items).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the properties set up we can modify them. In our case we want to check if the items label and title match a special pattern and if they do we want to fetch them from the language file instead.&lt;br /&gt;
The special pattern is &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[stringname]]&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; where stringname is the name of the string that we want to get from the language file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;text = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In the code above we do the following:&lt;br /&gt;
# Create an array $matches which will hold the stringname if the label matches the pattern.&lt;br /&gt;
# We attempt to match the label to the pattern. If it does the $matches array now contains the stringname.&lt;br /&gt;
# If it did match we call get string as shown.&lt;br /&gt;
&lt;br /&gt;
The third and final thing is to do the above again but this time for the title.&lt;br /&gt;
&lt;br /&gt;
With that done our transmutable_custom_menu_item class is complete. Next step is to make use of it.&lt;br /&gt;
&lt;br /&gt;
===Overriding render_custom_menu_item===&lt;br /&gt;
The next step is make use of the transmutable_custom_menu_item class we created previously. &lt;br /&gt;
&lt;br /&gt;
We can do this by overriding the &#039;&#039;&#039;core_renderer::render_custom_menu_item&#039;&#039;&#039; method within our renderers.php file as shown below.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function render_custom_menu_item(custom_menu_item $menunode) {&lt;br /&gt;
    $transmutedmenunode = new theme_themename_transmuted_custom_menu_item($menunode);&lt;br /&gt;
    return parent::render_custom_menu_item($transmutedmenunode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This is pretty simply, essentially we are using our transmuted_custom_menu_item class like a façade to the original custom_menu_item class by creating a new transmuted instance using the original.&lt;br /&gt;
Once we have the transmuted object we can call the original render_custom_menu_item method with it.&lt;br /&gt;
&lt;br /&gt;
And that is it! Congratulations if you got it this far.&lt;br /&gt;
&lt;br /&gt;
The only thing left to do is add strings to your themes language file as required!&lt;br /&gt;
&lt;br /&gt;
==Complete source==&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// theme/themename/renderers.php&lt;br /&gt;
&lt;br /&gt;
class theme_themename_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu(custom_menu $menu) {&lt;br /&gt;
        &lt;br /&gt;
        $mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (isloggedin() &amp;amp;&amp;amp; $mycourses &amp;amp;&amp;amp; $mycourses-&amp;gt;has_children()) {&lt;br /&gt;
            $branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
            $branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
            $branchtitle = $branchlabel;&lt;br /&gt;
            $branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
            $branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&lt;br /&gt;
            foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
                $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parent::render_custom_menu($menu);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu_item(custom_menu_item $menunode) {&lt;br /&gt;
        $transmutedmenunode = new theme_themename_transmuted_custom_menu_item($menunode);&lt;br /&gt;
        return parent::render_custom_menu_item($transmutedmenunode);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// theme/themename/lib.php&lt;br /&gt;
&lt;br /&gt;
class theme_themename_transmuted_custom_menu_item extends custom_menu_item {&lt;br /&gt;
    public function __construct(custom_menu_item $menunode) {&lt;br /&gt;
        parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
        $this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&lt;br /&gt;
        $matches = array();&lt;br /&gt;
        if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
            try {&lt;br /&gt;
                $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
            } catch (Exception $e) {&lt;br /&gt;
                $this-&amp;gt;text = $matches[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $matches = array();&lt;br /&gt;
        if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;title, $matches)) {&lt;br /&gt;
            try {&lt;br /&gt;
                $this-&amp;gt;title = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
            } catch (Exception $e) {&lt;br /&gt;
                $this-&amp;gt;title = $matches[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Adding courses and categories to the custom menu]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Extending_the_theme_custom_menu&amp;diff=57725</id>
		<title>Extending the theme custom menu</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Extending_the_theme_custom_menu&amp;diff=57725"/>
		<updated>2020-07-22T08:05:16Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: Remove superfluous word &amp;quot;quickly&amp;quot;. Fixed grammar of sentence.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Themes}}This is a quick tutorial that will run you through extending the custom menu by overriding your theme&#039;s renderer.&lt;br /&gt;
&lt;br /&gt;
This tutorial is primarily PHP coding, and ranges from moderate to advanced difficulty.&lt;br /&gt;
&lt;br /&gt;
==Before we begin==&lt;br /&gt;
First things first you need to know a little something about the custom menu. The custom menu is populated from the manually entered input in &#039;&#039;&amp;quot;Theme Settings&amp;quot;&#039;&#039;. Once the administrator has entered the custom menu items and saved them the following steps are what they go through in order to be displayed:&lt;br /&gt;
# The theme calls &#039;&#039;&#039;&#039;&#039;$OUTPUT-&amp;gt;custom_menu()&#039;&#039;&#039;&#039;&#039; which is the core_renderers method responsible for producing the custom menu.&lt;br /&gt;
# core_renderer::custom_menu() does the following:&lt;br /&gt;
## Checks to make sure the admin has added custom menu items.&lt;br /&gt;
## Creates a new &#039;&#039;&#039;&#039;&#039;custom_menu&#039;&#039;&#039;&#039;&#039; object. When the custom menu object is created it turns what ever the admin entered into a structured array of information.&lt;br /&gt;
## Calls core_renderer::render_custom_menu and gives it the custom_menu object.&lt;br /&gt;
# core_renderer::render_custom_menu is where the magic happens, it does the following.&lt;br /&gt;
## First it checks to make sure custom menu contains items.&lt;br /&gt;
## Initialises the JavaScript for the custom menu, this is the YUI3 menunode component.&lt;br /&gt;
## Creates the HTML base of the custom menu&lt;br /&gt;
## Then iterates through all of the items and calls the custom menu and passes them to another function that will turn them into HTML correctly.&lt;br /&gt;
&lt;br /&gt;
I&#039;m going to stop there, as there is no need at this point to go into any more detail. Don&#039;t worry if you are a little lost, it will get clearer as we start working through code.&lt;br /&gt;
&lt;br /&gt;
In this tutorial will we look at how to extend the theme&#039;s renderer in two different way.&lt;br /&gt;
# Add a dynamic My Courses branch to the custom menu that will display all of the courses a user is enrolled in.&lt;br /&gt;
# Get the custom menu to fetch strings from the language files rather than just static strings you type, allowing for a translatable custom menu.&lt;br /&gt;
&lt;br /&gt;
Before you start into this tutorial you should have read the following tutorial, or at least have a good knowledge of the the Moodle theme engine and Moodle development.&lt;br /&gt;
* [[Creating a theme based on boost]]&lt;br /&gt;
* [[Overriding a renderer]]&lt;br /&gt;
&lt;br /&gt;
As this is a quick tutorial I am going to assume you have created a theme, tested it and got it all working, and are already well on your way to becoming a theme guru.&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
Alright, as you have already have your theme ready to go preparation is pretty simple, we are going to go through and create (if you haven&#039;t already) the following files:&lt;br /&gt;
* theme/themename/lib.php&lt;br /&gt;
* theme/themename/renderers.php&lt;br /&gt;
* theme/themename/lang/en/themename.php&lt;br /&gt;
&lt;br /&gt;
Next step open up your themes config.php file and add the following configuration option to it (at the bottom):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$THEME-&amp;gt;rendererfactory = &#039;theme_overridden_renderer_factory&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you&#039;ve already got a custom renderer you will already have this line.&lt;br /&gt;
&lt;br /&gt;
And thats it! now we move on to extending the custom menu.&lt;br /&gt;
&lt;br /&gt;
==Adding the My Courses branch==&lt;br /&gt;
So the point of this extension is to add a &#039;&#039;&#039;My Courses&#039;&#039;&#039; branch to the end of the custom menu.&lt;br /&gt;
&lt;br /&gt;
The plan is to have the my courses branch and then within that branch have an entry for every course the user is enrolled in, much the same as the my courses branch of the navigation. &lt;br /&gt;
&lt;br /&gt;
In order to achieve this we need to add some items to the custom menu, the my courses branch and all of the courses within it. We can do this overriding the core_renderers &#039;&#039;&#039;render_custom_menu&#039;&#039;&#039; method, of more accuratly create our own render_custom_menu method that adds our items and then calls the original. Remember we only need to add items, we don&#039;t need to change what is being produced.&lt;br /&gt;
&lt;br /&gt;
So within our renderers.php file add the following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class theme_themename_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu(custom_menu $menu) {&lt;br /&gt;
        // Our code will go here shortly&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So that is pretty simple right?!&lt;br /&gt;
&lt;br /&gt;
Here we are defining our core_renderer which will contain our overridden method &#039;&#039;render_custom_menu&#039;&#039; which we have also defined there.&lt;br /&gt;
Note the definition of the render_custom_menu must be the same as the original, this means it must be &#039;&#039;&#039;protected&#039;&#039;&#039; and it must take one argument &#039;&#039;&#039;custom_menu $menu&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Next step is to write the code for our render_custom_menu method. As stated above we want to add a branch and courses to the end of it which we can do with the following bit of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&lt;br /&gt;
if (isloggedin() &amp;amp;&amp;amp; $mycourses &amp;amp;&amp;amp; $mycourses-&amp;gt;has_children()) {&lt;br /&gt;
    $branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
    $branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
    $branchtitle = $branchlabel;&lt;br /&gt;
    $branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
    $branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&lt;br /&gt;
    foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
        $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
return parent::render_custom_menu($menu);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So how this all works....&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This line is a little bit of smarts, what we are doing is getting the mycourses branch from the navigation. We could make all of the database calls and work it all out ourselves but this will be much better for performance and is easier!&lt;br /&gt;
&lt;br /&gt;
The next line of code is an &#039;&#039;if&#039;&#039; statement that checks three things&lt;br /&gt;
# The user is logged in, you must be logged in to see your courses.&lt;br /&gt;
# That we have a mycourses object, if the user isn&#039;t enrolled in anything they won&#039;t have a mycourses object.&lt;br /&gt;
# The the mycourses object has children, if it exists it should but it is better to be safe than get errors.&lt;br /&gt;
&lt;br /&gt;
Within the if statement we are doing two main things happening, the first is to add the branch to the menu:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
$branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
$branchtitle = $branchlabel;&lt;br /&gt;
$branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
$branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
When adding a new branch we need to give it three things:&lt;br /&gt;
# A label &#039;&#039;&#039;$branchlabel&#039;&#039;&#039;.&lt;br /&gt;
# A URL &#039;&#039;&#039;$branchurl&#039;&#039;&#039;.&lt;br /&gt;
# A title &#039;&#039;&#039;$branchtitle&#039;&#039;&#039; in this case I have just set it to the same as $branchlabel because I am lazy, you can make it anything you want.&lt;br /&gt;
# A sort order &#039;&#039;&#039;$branchsort&#039;&#039;&#039; this just needs to be high enough that it ends up on last place where we want it. Make it small to put it at the front.&lt;br /&gt;
&lt;br /&gt;
The final line of code from above simply adds it to the menu and collects a reference to it so that we can add courses to it.&lt;br /&gt;
&lt;br /&gt;
The second thing being done in the if statement is iterate through all of the courses in the mycourses object and add them to the branch. That is done with the following bit of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
    $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
So here we go through all of the mycourses objects children (which we know will be courses) and for each one we add an item to the branch.&lt;br /&gt;
When adding items here, like above, we need to give it the following:&lt;br /&gt;
# A label &#039;&#039;&#039;$coursenode-&amp;gt;get_content()&#039;&#039;&#039; returns us the text in the navigation node.&lt;br /&gt;
# A url &#039;&#039;&#039;$coursenode-&amp;gt;action&#039;&#039;&#039; which is the URL for the node.&lt;br /&gt;
# A title &#039;&#039;&#039;$coursenode-&amp;gt;get_title()&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
In this case we don&#039;t need to set a sort order because the navigation has already ordered them correctly!&lt;br /&gt;
&lt;br /&gt;
So now we are through the if statement and there is only one line of code left:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
return parent::render_custom_menu($menu);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This line of code simply calls the original &#039;&#039;&#039;core_renderer::render_custom_menu&#039;&#039;&#039; method to do all of the remaining work. Because we don&#039;t need to change the display at all we don&#039;t need to redo what it does, we can just use it!.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
How easy way that?! it&#039;s all done, if you open you site in your browser and log in the custom menu should now contain a my courses branch (providing you are enrolled in courses).&lt;br /&gt;
&lt;br /&gt;
==Loading labels from language files==&lt;br /&gt;
If you run a site that is available in more than one language &#039;&#039;&#039;and&#039;&#039;&#039; you want to make use of the custom menu then you will probably be very interested in this.&lt;br /&gt;
&lt;br /&gt;
The idea behind this extension is to load the labels and titles that get shown in the custom menu from the theme&#039;s language files rather than having just the fixed strings you type into the admin setting.&lt;br /&gt;
&lt;br /&gt;
In order to achieve this we need to do somehow override the custom_menu_item class so that it loads the strings from the database if they match a special pattern. We can then update the admin setting to use our patter and wallah! things should load from the language files.&lt;br /&gt;
&lt;br /&gt;
What makes this tricky is that we can&#039;t just override the custom_menu_item class, we also need to override the thing that makes create custom_menu_item instances which in this case is the core_renderer::render_custom_menu_item method.&lt;br /&gt;
&lt;br /&gt;
===Overriding the custom_menu_item class===&lt;br /&gt;
Within your themes lib.php file add the following lines of code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class theme_themename_transmuted_custom_menu_item extends custom_menu_item {&lt;br /&gt;
    public function __construct(custom_menu_item $menunode) {&lt;br /&gt;
        // Our code will go here&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
What we have done here is create an overridden custom_menu_item class called &#039;&#039;&#039;transmuted_custom_menu_item&#039;&#039;&#039;.&lt;br /&gt;
Within that class we are overriding the constructor, the constructor will be given the original menu item, and we will need to instantiate this object with the properties of the original. Once we have instantiated it, with the properties of the original, we can alter then as we like.&lt;br /&gt;
&lt;br /&gt;
Next we need to write the contents of the &#039;&#039;__construct&#039;&#039; method:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
$this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;text = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;title, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;title = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;title = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So there are essentially four things going on here.&lt;br /&gt;
&lt;br /&gt;
First we need to populate this object with the properties of the original item. We do this by calling the original constructor with $menunode properties as shown below.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Next we need to copy the properties that are not included in the original constructor, in this case there is only one &#039;&#039;&#039;$this-&amp;gt;children&#039;&#039;&#039;. This should be an array of all of this item&#039;s children (sub items).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now that we have all the properties set up we can modify them. In our case we want to check if the items label and title match a special pattern and if they do we want to fetch them from the language file instead.&lt;br /&gt;
The special pattern is &#039;&#039;&#039;&amp;lt;nowiki&amp;gt;[[stringname]]&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039; where stringname is the name of the string that we want to get from the language file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$matches = array();&lt;br /&gt;
if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
    try {&lt;br /&gt;
        $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
    } catch (Exception $e) {&lt;br /&gt;
        $this-&amp;gt;text = $matches[1];&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
In the code above we do the following:&lt;br /&gt;
# Create an array $matches which will hold the stringname if the label matches the pattern.&lt;br /&gt;
# We attempt to match the label to the pattern. If it does the $matches array now contains the stringname.&lt;br /&gt;
# If it did match we call get string as shown.&lt;br /&gt;
&lt;br /&gt;
The third and final thing is to do the above again but this time for the title.&lt;br /&gt;
&lt;br /&gt;
With that done our transmutable_custom_menu_item class is complete. Next step is to make use of it.&lt;br /&gt;
&lt;br /&gt;
===Overriding render_custom_menu_item===&lt;br /&gt;
The next step is make use of the transmutable_custom_menu_item class we created previously. &lt;br /&gt;
&lt;br /&gt;
We can do this by overriding the &#039;&#039;&#039;core_renderer::render_custom_menu_item&#039;&#039;&#039; method within our renderers.php file as shown below.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function render_custom_menu_item(custom_menu_item $menunode) {&lt;br /&gt;
    $transmutedmenunode = new theme_themename_transmuted_custom_menu_item($menunode);&lt;br /&gt;
    return parent::render_custom_menu_item($transmutedmenunode);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This is pretty simply, essentially we are using our transmuted_custom_menu_item class like a façade to the original custom_menu_item class by creating a new transmuted instance using the original.&lt;br /&gt;
Once we have the transmuted object we can call the original render_custom_menu_item method with it.&lt;br /&gt;
&lt;br /&gt;
And that is it! Congratulations if you got it this far.&lt;br /&gt;
&lt;br /&gt;
The only thing left to do is add strings to your themes language file as required!&lt;br /&gt;
&lt;br /&gt;
==Complete source==&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// theme/themename/renderers.php&lt;br /&gt;
&lt;br /&gt;
class theme_themename_core_renderer extends core_renderer {&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu(custom_menu $menu) {&lt;br /&gt;
        &lt;br /&gt;
        $mycourses = $this-&amp;gt;page-&amp;gt;navigation-&amp;gt;get(&#039;mycourses&#039;);&lt;br /&gt;
&lt;br /&gt;
        if (isloggedin() &amp;amp;&amp;amp; $mycourses &amp;amp;&amp;amp; $mycourses-&amp;gt;has_children()) {&lt;br /&gt;
            $branchlabel = get_string(&#039;mycourses&#039;);&lt;br /&gt;
            $branchurl   = new moodle_url(&#039;/course/index.php&#039;);&lt;br /&gt;
            $branchtitle = $branchlabel;&lt;br /&gt;
            $branchsort  = 10000;&lt;br /&gt;
&lt;br /&gt;
            $branch = $menu-&amp;gt;add($branchlabel, $branchurl, $branchtitle, $branchsort);&lt;br /&gt;
&lt;br /&gt;
            foreach ($mycourses-&amp;gt;children as $coursenode) {&lt;br /&gt;
                $branch-&amp;gt;add($coursenode-&amp;gt;get_content(), $coursenode-&amp;gt;action, $coursenode-&amp;gt;get_title());&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        return parent::render_custom_menu($menu);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function render_custom_menu_item(custom_menu_item $menunode) {&lt;br /&gt;
        $transmutedmenunode = new theme_themename_transmuted_custom_menu_item($menunode);&lt;br /&gt;
        return parent::render_custom_menu_item($transmutedmenunode);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// theme/themename/lib.php&lt;br /&gt;
&lt;br /&gt;
class theme_themename_transmuted_custom_menu_item extends custom_menu_item {&lt;br /&gt;
    public function __construct(custom_menu_item $menunode) {&lt;br /&gt;
        parent::__construct($menunode-&amp;gt;get_text(), $menunode-&amp;gt;get_url(), $menunode-&amp;gt;get_title(), $menunode-&amp;gt;get_sort_order(), $menunode-&amp;gt;get_parent());&lt;br /&gt;
        $this-&amp;gt;children = $menunode-&amp;gt;get_children();&lt;br /&gt;
&lt;br /&gt;
        $matches = array();&lt;br /&gt;
        if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;text, $matches)) {&lt;br /&gt;
            try {&lt;br /&gt;
                $this-&amp;gt;text = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
            } catch (Exception $e) {&lt;br /&gt;
                $this-&amp;gt;text = $matches[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $matches = array();&lt;br /&gt;
        if (preg_match(&#039;/^\[\[([a-zA-Z0-9\-\_\:]+)\]\]$/&#039;, $this-&amp;gt;title, $matches)) {&lt;br /&gt;
            try {&lt;br /&gt;
                $this-&amp;gt;title = get_string($matches[1], &#039;theme_themename&#039;);&lt;br /&gt;
            } catch (Exception $e) {&lt;br /&gt;
                $this-&amp;gt;title = $matches[1];&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Adding courses and categories to the custom menu]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Upgrade_API&amp;diff=56913</id>
		<title>Upgrade API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Upgrade_API&amp;diff=56913"/>
		<updated>2020-02-06T09:13:45Z</updated>

		<summary type="html">&lt;p&gt;Systemovich: Replace &amp;quot;module&amp;quot; in first sentence with more general term &amp;quot;plugin&amp;quot;. &amp;quot;Module&amp;quot; might be confused with activity plugins only. Grammar errors, like repeated words.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Upgrade API is how your plugin installs and upgrades itself, by keeping track of its own version.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Introduction==&lt;br /&gt;
By implementing this API in your plugin, Moodle will automatically create your database tables for you when you visit the Admin notifications page (.../admin/index.php). &lt;br /&gt;
&lt;br /&gt;
This process is controlled by three files within your plugin (there are other optional files you can use for various things. These are covered at the end of this document):&lt;br /&gt;
;[[version.php]] : This records the version of the plugin code (&#039;&#039;&#039;Please note:&#039;&#039;&#039; In Moodle installations below v2.0, this is not required for blocks, which use the version number returned by the block&#039;s init() method - see [[Blocks#Ready.2C_Set.2C_Go.21|the blocks development page]]). You must increase version in version.php after any change in /db/ folder, any change in javascript code, any new auto-loaded class, any new setting and also after any change in language pack, because a new version triggers the upgrade procedure and resets all caches.&lt;br /&gt;
;db/install.xml : This is used when someone installs your plugin for the first time.&lt;br /&gt;
;db/upgrade.php : This is used when someone who had an older version of your plugin installed upgrades to the latest version.&lt;br /&gt;
&lt;br /&gt;
In addition, Moodle also stores in the database the currently installed version of each plugin.&lt;br /&gt;
&lt;br /&gt;
In Moodle 1.x, this is stored in the mdl_config table, in a row with the name &#039;&#039;plugintype&#039;&#039;_&#039;&#039;pluginname&#039;&#039;_version. For example qtype_myqtype_version. The exception to this rule are modules and blocks. Installed module version numbers are stored in the mdl_modules table. Block version numbers are in mdl_block.&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.x, plugin version numbers are stored in the mdl_config_plugins table, with &#039;&#039;plugintype&#039;&#039;_&#039;&#039;pluginname&#039;&#039; in the plugin column, and &#039;version&#039; in the name column - with the same exception for modules and blocks.&lt;br /&gt;
&lt;br /&gt;
==A specific example==&lt;br /&gt;
&lt;br /&gt;
For the rest of this document, I will use a particular example, because it should make the explanation easier. You should be able to see how to generalise it.&lt;br /&gt;
&lt;br /&gt;
We will suppose that you are making a new question type myqtype. This is plugin type qtype, and the code will be in the question/type/myqtype folder. The currently installed version number will be stored in the (&#039;qtype_myqtype&#039;, &#039;version&#039;) row of the mdl_config_plugins table.&lt;br /&gt;
&lt;br /&gt;
In addition, we will just consider the first two releases of the plugin. The first release will have version number 2008080100, and will just use one database table mdl_myqtype_options, with two columns col1 and col2. Then we will suppose that the second release is 2008080200, and that requires an extra column, newcol, to be added to the mdl_myqtype_options table.&lt;br /&gt;
&lt;br /&gt;
==The files you need for the first release==&lt;br /&gt;
&lt;br /&gt;
In what follows, the bits of code you need to replace are &#039;&#039;&#039;in bold&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
;version.php&lt;br /&gt;
 $plugin-&amp;gt;version  = 2008080100; // Today&#039;s date in YYYYMMDD format, plus two additional digits&lt;br /&gt;
 $plugin-&amp;gt;requires = &#039;&#039;&#039;XXXXXXXXXX; // Moodle version - copy from $version in the top-level version.php file.&#039;&#039;&#039;&lt;br /&gt;
:Version numbers normally consist of the day&#039;s date in YYYYMMDD format, followed by two additional digits to allow for multiple versions in the same day, e.g. Sept 15, 2010 could have versions 2010091500, 2010091501, 2010091502, etc.&lt;br /&gt;
&lt;br /&gt;
;db/install.xml&lt;br /&gt;
:This file, which you should [[XMLDB editor|create with the XMLDB editor]], should contain the definition for your mdl_myqtype_options table, with the two columns col1 and col2.&lt;br /&gt;
&lt;br /&gt;
At this stage, you do not need a db/upgrade.php file.&lt;br /&gt;
&lt;br /&gt;
==The files you need for the second release==&lt;br /&gt;
&lt;br /&gt;
;version.php&lt;br /&gt;
 $plugin-&amp;gt;version  = 2008080200;&lt;br /&gt;
 $plugin-&amp;gt;requires = &#039;&#039;&#039;XXXXXXXXXX; // Copy the current value from the top-level version.php file.&#039;&#039;&#039;&lt;br /&gt;
;db/install.xml : This file should now contain the updated definition for your mdl_myqtype_options table, with three columns col1, col2 and newcol. You modify this file using the XMLDB editor.&lt;br /&gt;
;db/upgrade.php&lt;br /&gt;
:This file should contain the code that people need to run to upgrade from version 2008080100 of your plugin. That is, the code to add a column newcol to the mdl_myqtype_options table. You don&#039;t have to write this code yourself as the XMLDB editor will generate it for you. The upgrade.php file should contain a single function xmldb_qtype_myqtype_upgrade that looks a bit like:&lt;br /&gt;
 function xmldb_qtype_myqtype_upgrade($oldversion) {&lt;br /&gt;
     global $DB;&lt;br /&gt;
     $dbman = $DB-&amp;gt;get_manager();&lt;br /&gt;
 &lt;br /&gt;
     /// Add a new column newcol to the mdl_myqtype_options&lt;br /&gt;
     if ($oldversion &amp;lt; 2015031200) {&lt;br /&gt;
         &#039;&#039;&#039;// Code to add the column, generated by the &#039;View PHP Code&#039; option of the XMLDB editor.&#039;&#039;&#039;&lt;br /&gt;
     }&lt;br /&gt;
 &lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Hint: If you are modifying or adding a field/table, get the XMLDB editor to generate the PHP update code for you &#039;&#039;&#039;after&#039;&#039;&#039; making the changes in the editor. If you are deleting one, you need to generate the PHP code &#039;&#039;&#039;before&#039;&#039;&#039; making the change - or you won&#039;t be able to select the field/table to write the code for, because it no longer exists.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
==What happens when a user installs or upgrades your plugin==&lt;br /&gt;
&lt;br /&gt;
The process is triggered when an administrator goes to the Admin notifications page (.../admin/index.php). The code that does the work is the upgrade_plugins function in lib/upgradelib.php and reading this code is the best way to find out exactly what happens. In pseudo-code, what it does is:&lt;br /&gt;
&lt;br /&gt;
 For each plugin of this type (e.g. all qtype plugins) {&lt;br /&gt;
     // For the body of this loop, suppose the current plugin being processed is myqtype.&lt;br /&gt;
 &lt;br /&gt;
     Check that question/type/myqtype/version.php, .../db/upgrade.php and .../db/install.xml exist.&lt;br /&gt;
 &lt;br /&gt;
     if (get_config(&#039;qtype_myqtype&#039;, &#039;version&#039;) exists, and is less than the number in version.php) {&lt;br /&gt;
         Call the upgrade function xmldb_qtype_myqtype_upgrade from upgrade.php,&lt;br /&gt;
                 passing the old version number that says what is currently installed&lt;br /&gt;
         set_config(&#039;version&#039;, &#039;&#039;latest number from version.php&#039;&#039;, &#039;qtype_myqtype&#039;)&lt;br /&gt;
                 to record what is currently installed&lt;br /&gt;
 &lt;br /&gt;
     } else if (get_config(&#039;qtype_myqtype&#039;, &#039;version&#039;) does not exist) {&lt;br /&gt;
         Create the tables from the definitions in install.xml&lt;br /&gt;
         set_config(&#039;version&#039;, &#039;&#039;latest number from version.php&#039;&#039;, &#039;qtype_myqtype&#039;)&lt;br /&gt;
                 to record what is currently installed&lt;br /&gt;
     }&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Of course, it is a bit more complex that than. However, the code in the upgrade_plugins is quite clear, and I encourage you to go and have a look at it so you can see all the details of how it works.&lt;br /&gt;
&lt;br /&gt;
Let us now look at some worked examples:&lt;br /&gt;
&lt;br /&gt;
===User installs version 2008080100 of myqtype===&lt;br /&gt;
&lt;br /&gt;
To start with, the mdl_myqtype_options does not exist, and there will not be a (&#039;qtype_myqtype&#039;, &#039;version&#039;) row in the mdl_config_plugins table.&lt;br /&gt;
&lt;br /&gt;
# The user will unzip myqtype.zip into the question/type folder.&lt;br /&gt;
# The user will visit the Admin notifications page.&lt;br /&gt;
# This will trigger Moodle to search for plugings to upgrade. It will find that the code for the qtype_myqtype plugin is now present, but there is no trace of it in the database, so it will install the plugin from the install.xml file.&lt;br /&gt;
&lt;br /&gt;
At the end of this process, the mdl_myqtype_options table will exist with the two columns col1 and col2; and the (&#039;qtype_myqtype&#039;, &#039;version&#039;) row in the mdl_config_plugins table will contain 2008080100.&lt;br /&gt;
&lt;br /&gt;
===User upgrades from version 2008080100 to version 2008080200 of myqtype===&lt;br /&gt;
&lt;br /&gt;
To start with, the mdl_myqtype_options table will exist with the two columns col1 and col2; and the (&#039;qtype_myqtype&#039;, &#039;version&#039;) row in the mdl_config_plugins table will contain 2008080100.&lt;br /&gt;
&lt;br /&gt;
# The user will delete the old question/type/myqtype folder.&lt;br /&gt;
# The user will unzip the new myqtype.zip into the question/type folder.&lt;br /&gt;
# The user will visit the Admin notifications page.&lt;br /&gt;
# This will trigger Moodle to search for plugings to upgrade. It will find that the code for version 2008080200 the qtype_myqtype plugin is now present, but the installed version of the the database tables (&#039;qtype_myqtype&#039;, &#039;version&#039;) is 2008080100. Therefore, it will call xmldb_qtype_myqtype_upgrade from upgrade.php, passing 2008080100 as the $oldversion argument.&lt;br /&gt;
&lt;br /&gt;
At the end of this process, the mdl_myqtype_options table will now have three columns col1, col2 and newcol; and the (&#039;qtype_myqtype&#039;, &#039;version&#039;) row in the mdl_config_plugins table will contain 2008080200.&lt;br /&gt;
&lt;br /&gt;
===User installs version 2008080200 of myqtype into a clean Moodle install===&lt;br /&gt;
&lt;br /&gt;
To start with, the mdl_myqtype_options does not exist, and there will not be a (&#039;qtype_myqtype&#039;, &#039;version&#039;) row in the mdl_config_plugins table.&lt;br /&gt;
&lt;br /&gt;
# The user will unzip the 2008080200 version of myqtype.zip into the question/type folder.&lt;br /&gt;
# The user will visit the Admin notifications page.&lt;br /&gt;
# This will trigger Moodle to search for plugings to upgrade. It will find that the code for the qtype_myqtype plugin is now present, but there is no trace of it in the database, so it will install the plugin from the install.xml file.&lt;br /&gt;
&lt;br /&gt;
At the end of this process, the mdl_myqtype_options table will exist with three columns col1, col2 and newcol; and the (&#039;qtype_myqtype&#039;, &#039;version&#039;) row in the mdl_config_plugins table will contain 2008080200.&lt;br /&gt;
&lt;br /&gt;
== Upgrade code restrictions ==&lt;br /&gt;
&lt;br /&gt;
Within an upgrade, there are restrictions on the functions your code should call, because the system has not been fully updated.&lt;br /&gt;
&lt;br /&gt;
* All upgrade code can use the basic database API ($DB-&amp;gt;... functions).&lt;br /&gt;
* In a &#039;&#039;&#039;plugin&#039;&#039;&#039;, upgrade code should not call &#039;&#039;&#039;any plugin functions&#039;&#039;&#039;. (For example, if your plugin has a function that changes frog settings to &#039;green&#039;, and you need to do this during upgrade, then you should not call this function; instead, manually update the database rows so that the frog settings become green.) However, &#039;&#039;&#039;you should call core functions&#039;&#039;&#039; rather than making core changes in database.&lt;br /&gt;
* In &#039;&#039;&#039;core&#039;&#039;&#039;, upgrade code should not even call &#039;&#039;&#039;any core functions&#039;&#039;&#039; (For example, if you need to add a calendar event, this should be done by inserting into a database table rather than calling a function to add the event.) Certain functions marked with a comment such as set_config and get_config are excepted.&lt;br /&gt;
&lt;br /&gt;
The reason for this is the state of the system during upgrade.&lt;br /&gt;
&lt;br /&gt;
During core upgrade the state is as follows:&lt;br /&gt;
&lt;br /&gt;
* Core data: &#039;&#039;&#039;Old&#039;&#039;&#039;. &lt;br /&gt;
* Plugin data: &#039;&#039;&#039;Old&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Core functions expect core data to be in the Current state, so it is not safe to call them, unless the following is present in the function&#039;s docblock: &amp;quot;NOTE: this function is called from lib/db/upgrade.php&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
During plugin upgrade the state is as follows:&lt;br /&gt;
&lt;br /&gt;
* Core data: &#039;&#039;&#039;Current&#039;&#039;&#039;. (Because core upgrade runs before plugin upgrade.)&lt;br /&gt;
* Plugin data: &#039;&#039;&#039;Old&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Core functions are now safe to call because the core data is in Current state. But plugin functions, which expect data to be in the Current state, are not safe.&lt;br /&gt;
&lt;br /&gt;
==Summary==&lt;br /&gt;
&lt;br /&gt;
The first time a user installs any version of your plugin, the install.xml file will be used to create all the required database tables. Therefore install.xml should always contain the definition of the up-to-date database structure. Moodle recognises this situation because there is a version.php file on disc, but there is no (&#039;&#039;plugintype&#039;&#039;_&#039;&#039;pluginname&#039;&#039;, version) value in the mdl_config_plugins table.&lt;br /&gt;
&lt;br /&gt;
If the user already had a version of your plugin installed, and then upgrades to a newer version, Moodle will detect this because the version.php file will contain a newer version number than the (&#039;&#039;plugintype&#039;&#039;_&#039;&#039;pluginname&#039;&#039;, version) value in the mdl_config_plugins table. In this case, Moodle will run the code in the upgrade.php file, passing in the old version number, so that the correct bits of upgrade can be run, as controlled by the if ($oldversion &amp;lt; XXXXXXXXXX) blocks of code.&lt;br /&gt;
&lt;br /&gt;
The contents of the install.xml and upgrade.php files should be generated using the XMLDB editor.&lt;br /&gt;
&lt;br /&gt;
==Other things that can be in the db folder==&lt;br /&gt;
&lt;br /&gt;
Of these, only install.php relates to creating the necessary database structure. The other files are mainly about providing the other meta-data that is required when the plugin is installed. I have tried to link to other documentation that goes into detail where possible.&lt;br /&gt;
&lt;br /&gt;
===install.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 2.0 and later)&lt;br /&gt;
&lt;br /&gt;
If you define a function like xmldb_qtype_myqtype_install(), this PHP code will be executed when your plugin is installed. This is an opportunity to do things that you cannot do with install.xml. It&#039;s executed immediately after the DB schema associated with the component (install.xml) is created.&lt;br /&gt;
&lt;br /&gt;
(Moodle 1.9)&lt;br /&gt;
&lt;br /&gt;
An install function can be defined in lib.php in the root directory of your module. The install function must have the name qtype_install() and takes no arguments (n.b. this is called from lib/adminlib.php after install.xml is parsed)&lt;br /&gt;
&lt;br /&gt;
===uninstall.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 2.0 and later)&lt;br /&gt;
&lt;br /&gt;
Balancing the previous feature, it&#039;s also possible to define one function like xmldb_qtype_myqtype_uninstall(), that will be executed when your plugin is uninstalled, before dropping its DB schema.&lt;br /&gt;
&lt;br /&gt;
===access.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 1.7 and later)&lt;br /&gt;
&lt;br /&gt;
Use to define the [[Roles#Capabilities|capabilities]] that this plugin handles with the [[Access API]]. You must increase version in version.php after adding new capabilities.&lt;br /&gt;
&lt;br /&gt;
===events.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 1.9(?) and later)&lt;br /&gt;
&lt;br /&gt;
Used to define the events this plugin sends to the [[Events_API|Events API]]. You must increase version in version.php after modifying or adding new events.&lt;br /&gt;
&lt;br /&gt;
===log.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 2.0 and later)&lt;br /&gt;
&lt;br /&gt;
Used to describe the type of log entries that this plugin creates. See the [[Logging API#Mod/*/db/log.php Files| log.php section]] of the [[Logging API]] for more information. You must increase version in version.php after any change.&lt;br /&gt;
&lt;br /&gt;
===messages.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 2.0 and later)&lt;br /&gt;
&lt;br /&gt;
Used to define the messages this plugin sends through the [[Message API|Messaging API]]. You must increase version in version.php after any change.&lt;br /&gt;
&lt;br /&gt;
===services.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 2.0 and later)&lt;br /&gt;
&lt;br /&gt;
Used to define the functions and services this plugin publishes through the [[Web services API]]. Usually all those functions are part of the [[External functions API]]. You must increase version in version.php after any change.&lt;br /&gt;
&lt;br /&gt;
===upgradelib.php===&lt;br /&gt;
&lt;br /&gt;
Optional file where upgrade code can be grouped under some &#039;&#039;&#039;helper functions&#039;&#039;&#039; to be used in the upgrade.php file. If needed, this file must be &#039;&#039;&#039;manually required&#039;&#039;&#039; once from upgrade.php. Its main goal is to keep the upgrade.php scripts reduced and clear (this cannot contain any function themselves apart from the xmldb_xxx_upgrade() one).&lt;br /&gt;
&lt;br /&gt;
It&#039;s &#039;&#039;&#039;important&#039;&#039;&#039; to note that the upgradelib.php files should always be performing any task using raw - low level - database access exclusively, &#039;&#039;&#039;avoiding any use of the Moodle APIs&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===mod/.../db/subplugins.php===&lt;br /&gt;
&lt;br /&gt;
(Moodle 2.0 and later)&lt;br /&gt;
&lt;br /&gt;
This only applies to activity modules, not other types of plugin. It is a way to allow an activity module to have its own sorts of plugins. For example workshop allocation schemes, or quiz reports.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Language packs==&lt;br /&gt;
&lt;br /&gt;
Do not forget to increase version number after modifying lang/en/type_yourplugin.php language file. See [[Languages/AMOS]] section AMOS script for more information.&lt;br /&gt;
&lt;br /&gt;
==Upgrade API Cheatsheet==&lt;br /&gt;
&lt;br /&gt;
The Upgrade API is &#039;&#039;&#039;related with a lot&#039;&#039;&#039; of different files and APIs (access, event, log, webservice...) as far as it&#039;s the API used to install/upgrade all those artifacts. The previous sections have tried to list all those dependencies when possible. &lt;br /&gt;
&lt;br /&gt;
Also, the Upgrade API &#039;&#039;&#039;does a very intensive use&#039;&#039;&#039; of other APIs ([[Data definition API|ddl]], [[Data manipulation API|dml]]) and tools (the XMLDB editor...) in order to proceed with the modifications of the Moodle system.&lt;br /&gt;
&lt;br /&gt;
Once stated the above, we could summarise the API as the &#039;&#039;&#039;collection of a few files and functions&#039;&#039;&#039;, here they are:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The files&#039;&#039;&#039;: For each component we can have, under its &amp;quot;db&amp;quot; directory.&lt;br /&gt;
* &#039;&#039;&#039;version.php&#039;&#039;&#039;: Where the $version is specified and, if bumped, the upgrade machinery will be launched and all caches reset. Bump up version after changing /db/, /lang/, theme or JavaScript.&lt;br /&gt;
* &#039;&#039;&#039;install.xml&#039;&#039;&#039;: XMLDB definition of the DB schema. generated with the XMLDB Editor.&lt;br /&gt;
* &#039;&#039;&#039;install.php&#039;&#039;&#039;: Post-install file executed once the schema has been created.&lt;br /&gt;
* &#039;&#039;&#039;uninstall.php&#039;&#039;&#039;: Pre-uninstall file executed before the schema is dropped.&lt;br /&gt;
* &#039;&#039;&#039;upgrade.php&#039;&#039;&#039;: Ordered list of upgrade steps, each one performing a well-defined task. &lt;br /&gt;
* &#039;&#039;&#039;upgradelib.php&#039;&#039;&#039;: Library files composed of helper functions to be used by upgrade.php.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;The functions&#039;&#039;&#039;: With different names for different components, but available to all them:&lt;br /&gt;
* &#039;&#039;&#039;xmldb_[main|[[Frankenstyle|frankenstyle]]]_install()&#039;&#039;&#039;: to be used in install.php files.&lt;br /&gt;
* &#039;&#039;&#039;xmldb_[main|frankenstyle]_uninstall()&#039;&#039;&#039;: to be used in uninstall.php files.&lt;br /&gt;
* &#039;&#039;&#039;xmldb_[main|frankenstyle]_upgrade()&#039;&#039;&#039;: to be used in upgrade.php files.&lt;br /&gt;
* &#039;&#039;&#039;upgrade_set_timeout()&#039;&#039;&#039;: to be used within the upgrade steps in upgrade.php files, in order to grant more time to the step.&lt;br /&gt;
* &#039;&#039;&#039;upgrade_[main|mod|block|plugin]_savepoint()&#039;&#039;&#039;: to consider one upgrade step completed and reset timeouts. Avoids double executions.&lt;br /&gt;
&lt;br /&gt;
Of course, for practical examples of the use of this API it&#039;s &#039;&#039;&#039;highly recommended to examine and understand current code&#039;&#039;&#039;. Everything is out there.&lt;br /&gt;
&lt;br /&gt;
==Database upgrades and stable branches==&lt;br /&gt;
&lt;br /&gt;
The simple rule is, never make any database changes on a stable branch. You only need to read this section in the rare situations where a database change on the stable branch is unavoidable.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Warning!!! advanced material follows.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Suppose, in order to fix a bug, you need to make a database change in Moodle 1.9.3+ (which must also be merged into HEAD). The root of the problem is that people may upgrade their Moodle in three different ways, which &lt;br /&gt;
&lt;br /&gt;
* Upgrade from &amp;lt;=1.9.3 to 1.9.4 - this executes the ugprade script on the 1.9 branch.&lt;br /&gt;
* Upgrade from &amp;lt;=1.9.3 directly to &amp;gt;=2.0 - this executes the upgrade script on the HEAD branch.&lt;br /&gt;
* Upgrade from 1.9.4 to &amp;gt;=2.0 - in this case, you must ensure that the upgrade on HEAD is not executed.&lt;br /&gt;
&lt;br /&gt;
The normal way to do this is ensure that your database upgrade is idempotent. That is, it does not matter if you do it twice. So for example, instead of doing&lt;br /&gt;
&lt;br /&gt;
        $dbman-&amp;gt;create_table($table);&lt;br /&gt;
&lt;br /&gt;
you should do&lt;br /&gt;
&lt;br /&gt;
        if (!$dbman-&amp;gt;table_exists($table)) {&lt;br /&gt;
            $dbman-&amp;gt;create_table($table);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
You should also think about what version numbers to put in your version.php file on each branch. Above all, test carefully.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[XMLDB_Documentation|XMLDB_Documentation]]&lt;br /&gt;
* [[Coding|Coding guidelines]]&lt;br /&gt;
* [[DDL functions|DDL functions]]&lt;br /&gt;
* [[XMLDB defining an XML structure|install.xml file documentation]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
[[Category:XMLDB]]&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
&lt;br /&gt;
[[es: API de Actualización]]&lt;/div&gt;</summary>
		<author><name>Systemovich</name></author>
	</entry>
</feed>