<?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=Libertymoodle</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=Libertymoodle"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Libertymoodle"/>
	<updated>2026-04-18T19:02:12Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Extending_the_theme_custom_menu&amp;diff=57889</id>
		<title>Talk:Extending the theme custom menu</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Extending_the_theme_custom_menu&amp;diff=57889"/>
		<updated>2020-10-01T13:19:34Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Restrict menu options by Moodle Roles */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;In the renderers.php file (in my project) I had to add the php tags &amp;lt;?php ?&amp;gt;, because they were missing on the original text. Fixed my problem, but I&#039;m not sure whether I should edit the original post.&lt;br /&gt;
-----&lt;br /&gt;
&lt;br /&gt;
Is it possible to add options to the custom menu that are only visible to people who have a certain role in Moodle? If so, can the details be added here?&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 13:19, 1 October 2020 (UTC)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=57653</id>
		<title>Course module</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=57653"/>
		<updated>2020-06-24T06:34:23Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* url */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Summary==&lt;br /&gt;
A course module (often abbreviated &#039;cm&#039;) represents each of the activities and resources found in a course. It contains information about which course and section the activity / resource is displayed on, as well as details about the visibility, group and completion status of the activity.&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
The data for the course module is stored in the database table &#039;mdl_course_modules&#039; (the &#039;mdl_&#039; part will be different if you have chosen a non-default prefix for your database tables). The fields in this table link it to a number of other tables in the database. &lt;br /&gt;
* The &#039;course&#039; field links to the &#039;mdl_course&#039; table, which contains everything you need to know about a course. &lt;br /&gt;
* The &#039;module&#039; table links to the &#039;mdl_modules&#039; table, which gives information about the type of the module (e.g. &#039;quiz&#039;, &#039;resource&#039;) as well as its current version number. &lt;br /&gt;
* After looking up the type of the module, the rest of the details about this module can be found by looking up the &#039;instance&#039; value (from the &#039;mdl_course_modules&#039; table) in the &#039;mdl_{type}&#039; table. Here you can find the name and introductory paragraph for the activity / resource, as well as information that is specific to the type of activity being looked at.&lt;br /&gt;
&lt;br /&gt;
You can quickly gather all of this information, by using the &#039;get_fast_modinfo($course)&#039; function. The easiest way to understand the data returned is to use the following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$course = $DB-&amp;gt;get_record(&#039;course&#039;, array(&#039;id&#039; =&amp;gt; $courseid));&lt;br /&gt;
$info = get_fast_modinfo($course);&lt;br /&gt;
print_object($info);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
The cmid (course module id) is used widely throughout Moodle to identify a specific activity / resource. Some of the most important uses are:&lt;br /&gt;
* When linking to a modules &#039;view.php&#039; script, it is passed as the &#039;id&#039; parameter&lt;br /&gt;
* To get the &#039;context&#039; for the module (used when checking user capabilities or linking files to an activity), via the function call &#039;context_module::instance($cmid)&#039; (before Moodle 2.2 this was &#039;get_context_instance(CONTEXT_MODULE, $cmid)&#039;)&lt;br /&gt;
* Every log entry in &#039;mdl_log&#039; that relates to a specific activity has the &#039;cmid&#039; field set&lt;br /&gt;
&lt;br /&gt;
==More documentation==&lt;br /&gt;
* [[Module visibility and display]]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/course_modinfo.html course_modinfo PHPdocs]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/cm_info.html cminfo PHPdocs]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=255653#p1108750 mdl_course_modules table forum discussion]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=57645</id>
		<title>Course module</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Course_module&amp;diff=57645"/>
		<updated>2020-06-23T08:16:44Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Add mdl_course_modules forum discussion link */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Summary==&lt;br /&gt;
A course module (often abbreviated &#039;cm&#039;) represents each of the activities and resources found in a course. It contains information about which course and section the activity / resource is displayed on, as well as details about the visibility, group and completion status of the activity.&lt;br /&gt;
&lt;br /&gt;
==Database tables==&lt;br /&gt;
The data for the course module is stored in the database table &#039;mdl_course_modules&#039; (the &#039;mdl_&#039; part will be different if you have chosen a non-default prefix for your database tables). The fields in this table link it to a number of other tables in the database. &lt;br /&gt;
* The &#039;course&#039; field links to the &#039;mdl_course&#039; table, which contains everything you need to know about a course. &lt;br /&gt;
* The &#039;module&#039; table links to the &#039;mdl_modules&#039; table, which gives information about the type of the module (e.g. &#039;quiz&#039;, &#039;resource&#039;) as well as its current version number. &lt;br /&gt;
* After looking up the type of the module, the rest of the details about this module can be found by looking up the &#039;instance&#039; value (from the &#039;mdl_course_modules&#039; table) in the &#039;mdl_{type}&#039; table. Here you can find the name and introductory paragraph for the activity / resource, as well as information that is specific to the type of activity being looked at.&lt;br /&gt;
&lt;br /&gt;
You can quickly gather all of this information, by using the &#039;get_fast_modinfo($course)&#039; function. The easiest way to understand the data returned is to use the following code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
global $DB;&lt;br /&gt;
$course = $DB-&amp;gt;get_record(&#039;course&#039;, array(&#039;id&#039; =&amp;gt; $courseid));&lt;br /&gt;
$info = get_fast_modinfo($course);&lt;br /&gt;
print_object($info);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
The cmid (course module id) is used widely throughout Moodle to identify a specific activity / resource. Some of the most important uses are:&lt;br /&gt;
* When linking to a modules &#039;view.php&#039; script, it is passed as the &#039;id&#039; parameter&lt;br /&gt;
* To get the &#039;context&#039; for the module (used when checking user capabilities or linking files to an activity), via the function call &#039;context_module::instance($cmid)&#039; (before Moodle 2.2 this was &#039;get_context_instance(CONTEXT_MODULE, $cmid)&#039;)&lt;br /&gt;
* Every log entry in &#039;mdl_log&#039; that relates to a specific activity has the &#039;cmid&#039; field set&lt;br /&gt;
&lt;br /&gt;
==More documentation==&lt;br /&gt;
* [[Module visibility and display]]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/course_modinfo.html course_modinfo PHPdocs]&lt;br /&gt;
* [http://phpdocs.moodle.org/HEAD/core/lib/cm_info.html cminfo PHPdocs]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=255653 mdl_course_modules table forum discussion]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Moodle_3.8_release_notes&amp;diff=57257</id>
		<title>Talk:Moodle 3.8 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Moodle_3.8_release_notes&amp;diff=57257"/>
		<updated>2020-04-07T11:09:45Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* PHP v7.4 support */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Server requirements==&lt;br /&gt;
&lt;br /&gt;
Does Moodle 3.8 run under PHP version 7.4? MDL-66260 implies that full suport for PHP 7.4 is still under development. This doc should be specific about support for PHP 7.4.&lt;br /&gt;
&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 11:08, 7 April 2020 (UTC)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Moodle_3.8_release_notes&amp;diff=57256</id>
		<title>Talk:Moodle 3.8 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Moodle_3.8_release_notes&amp;diff=57256"/>
		<updated>2020-04-07T11:09:00Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* PHPv7.4 support */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Server requirements==&lt;br /&gt;
&lt;br /&gt;
Does Moodle 3.8 run under PHP version 7.4? MDL-66260 implies that full suport for PHP 7.4 is still under development.&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 11:08, 7 April 2020 (UTC)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Better_handling_of_overdue_quiz_attempts&amp;diff=55883</id>
		<title>Better handling of overdue quiz attempts</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Better_handling_of_overdue_quiz_attempts&amp;diff=55883"/>
		<updated>2019-04-04T08:16:57Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* See also links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Handling of overdue quiz attempts&lt;br /&gt;
|state = Implementation complete. Testing.&lt;br /&gt;
|tracker = MDL-3030, MDL-4309&lt;br /&gt;
|discussion = [http://moodle.org/mod/forum/discuss.php?d=201355 Quiz forum thread about testing] [http://moodle.org/mod/forum/discuss.php?d=188534 Old Quiz forum thread about the proposal]&lt;br /&gt;
|assignee = [[User:Tim Hunt|Tim Hunt]]&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.3}}&lt;br /&gt;
&lt;br /&gt;
There is a tricky issue to do with what happens exactly when time runs on on a quiz. On the one hand, we want to let students use every second of time. On the other hand, the end of a quiz is often a time of high server load, and so Moodle is likely to responding slowly. Therefore, we have to prevent students from cheating on the time-limit while still processing their last-minute submission even if the server is heavily loaded.&lt;br /&gt;
&lt;br /&gt;
There is also the problem of what happens if the student just logs out and does not submit at all. At the moment the attempt goes into a sort of limbo where Moodle can&#039;t really do anything with it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What happens at the moment==&lt;br /&gt;
&lt;br /&gt;
Currently there are only really two states a quiz attempt can be in, and they are distinguished by whether quiz_attempts.timefinish is 0 or contains a time-stamp.&lt;br /&gt;
&lt;br /&gt;
[[Image:Quiz_attempt_states_now.png]]&lt;br /&gt;
&lt;br /&gt;
At most one attempt is allowed to be in the &#039;&#039;&#039;In progress&#039;&#039;&#039; state at any time.&lt;br /&gt;
&lt;br /&gt;
After time expires, (either because the time limit runs out, or the close date passes) the attempt is in a weird state. Well, not really, the attempt is still considered to be &#039;&#039;&#039;In progress&#039;&#039;&#039;, but the student is no longer allowed to access it, so there is no way to get at the &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; button to submit it. Also, if the quiz allows more than one attempt, the student cannot start a new attempt, because they already have an &#039;&#039;&#039;In progress&#039;&#039;&#039; attempt (which they are not allowed to access!)&lt;br /&gt;
&lt;br /&gt;
The known work-around is, as teacher, to:&lt;br /&gt;
# edit quiz settings to allow more time;&lt;br /&gt;
# login-as the student and submit the quiz;&lt;br /&gt;
# set the time-limit or close data back to what it should be.&lt;br /&gt;
This is a real pain.&lt;br /&gt;
&lt;br /&gt;
Before reading on, you may wish to remind yourself of the [[Quiz user interface overview]], so you know what the key scripts view/startattempt/attempt/processattempt/summar/review.php each do.&lt;br /&gt;
&lt;br /&gt;
To document the two existing transitions in some detail (note, all transitions are logged, I have not bothered to say that every time):&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Start attempt===&lt;br /&gt;
&lt;br /&gt;
Goes to: In progress&lt;br /&gt;
&lt;br /&gt;
Allowed when: If the student does not currently have any &#039;&#039;&#039;In progress&#039;&#039;&#039; attempt, and if they meet all the conditions imposed by the [[Quiz access rules|access rules]], they may start one.&lt;br /&gt;
&lt;br /&gt;
How it is done: The student clicks the &#039;&#039;&#039;Start attempt&#039;&#039;&#039; button on view.php. Technically, this takes the form of a POST request to startattempt.php.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# The attempt, and corresponding $quba, are created.&lt;br /&gt;
# They are initialised by adding all the questions, which may depend on randomisation, and &#039;each attempt builds on last&#039;.&lt;br /&gt;
# The attempt and all associated data is written to the database.&lt;br /&gt;
# A quiz_attempt_started event is raised. (This even it not used in standard Moodle.)&lt;br /&gt;
&lt;br /&gt;
===Transition: Submit all and finish===&lt;br /&gt;
&lt;br /&gt;
Goes from: In progress&lt;br /&gt;
&lt;br /&gt;
Goes to: Finished&lt;br /&gt;
&lt;br /&gt;
Allowed when: The student has an &#039;&#039;&#039;In progress&#039;&#039;&#039; attempt, which they are currently allowed to access according to the access rules. In particular, where the time limit has not run out, and the close date has not passed.&lt;br /&gt;
&lt;br /&gt;
How it is done: Either&lt;br /&gt;
* The student clicks the &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; button on summary.php; or&lt;br /&gt;
* Time runs out while the student is working on the quiz, and so the quiz is submitted automatically (if JavaScript is enabled).&lt;br /&gt;
Technically, this takes the form of a POST request to processattempt.php, althought the code that does the work is the quiz_attempt::finish_attempt method in attemptlib.php.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# All questions that are not already finishes are finished.&lt;br /&gt;
# The updated question states are written to the database.&lt;br /&gt;
# The quiz_attempt record is updated with the timefinish and the total mark.&lt;br /&gt;
# The overall quiz grade (combining all the student&#039;s attempt scores) is updated, and stored in the gradebook.&lt;br /&gt;
# A quiz_attempt_submitted event is raised. (This is used by the quiz itself to send out any tutor or student notification messages that are enabled.)&lt;br /&gt;
&lt;br /&gt;
==Rough outline of the solution==&lt;br /&gt;
&lt;br /&gt;
We will introduce a new quiz settings &#039;&#039;&#039;When time expires&#039;&#039;&#039; and &#039;&#039;&#039;Grace period&#039;&#039;&#039;. When time expires is the strategy we will use for overdue attempts. For some strategies, they will need an amount of extra time that is the grace period. The possible strategies are:&lt;br /&gt;
&lt;br /&gt;
# Submit attempt automatically,&lt;br /&gt;
# Allow a grace period to submit, but not change any responses, or&lt;br /&gt;
# That&#039;s it. Tough luck! - &#039;&#039;we need a better name for this!&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
1. Corresponds to doing an automatic submit all and finish. 3. Corresponds to automatically moving the attempt to the &#039;&#039;&#039;Abandoned state&#039;&#039;&#039;. See below. 2. is more interesting (and is what the OU wants for assessed tests).&lt;br /&gt;
&lt;br /&gt;
If the student has not submitted their attempt when time runs out, then the attempt moves into the &#039;&#039;&#039;Overdue&#039;&#039;&#039; state. In this state, when the student tries to get to the quiz attempt, then can only go to the Summary page, where all they can do is to click the &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; button.&lt;br /&gt;
&lt;br /&gt;
If they finish submitted before the grace period runs out, then their attempt is counted.&lt;br /&gt;
&lt;br /&gt;
If the student still does not submit, then the attempt moves into the &#039;&#039;&#039;Abandoned&#039;&#039;&#039; state. This means that the student is not prevented from starting a new attempt, if the quiz allows it.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Question: should we allow the student to abandon the current attempt at any time? For example, if an interactive quiz allows multiple attempts, and the student has got off to a bad start, should we let them abandon and start again, or should we force them to &#039;&#039;&#039;Submit all and finish&#039;&#039;&#039; if they want a new attempt? - for now we will not allow students to abandon any attempt.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
In addition, we will start storing the quiz_attempt.state explicitly in the database, rather than relying on deducing it from timefinish or other columns. In a sense this is redundant information, but since significant things happen when the state changes (e.g. a message might be sent) I think making the state, and hence the state transition, explicit, will make the code clearer.&lt;br /&gt;
&lt;br /&gt;
We will need code that detects when an attempt is in the &#039;wrong&#039; state. For example, if a state is stored in the database as &#039;&#039;&#039;In progress&#039;&#039;&#039;, but time has now expired, then we will need to detect that and correct it by triggering the correct state transition. I think we need to do this in two ways:&lt;br /&gt;
# Whenever we load an attempt from the database. This ensure that if the user is actively working on the quiz when a state transition is supposed to happen, they will immediately see the attempt change state.&lt;br /&gt;
# We will need to add a cron script that detects attempts becoming overdue when no-one is looking at them.&lt;br /&gt;
(Note there is a subtlety, the JavaScript timer that runs in the user&#039;s browser will try to automatically trigger a submit, they may be happening at the same time as a teacher is reviewing the attempt (which might trigger 1) and cron may also be running at the same time (which might trigger 2). Therefore, we need a clear protocol to avoid nasty race-conditions.&lt;br /&gt;
&lt;br /&gt;
Actually, a possible third way (instead of, or in addition to cron). Perhaps we should detect this when the quiz settings (or overrides) are edited, and check all attempts then and trigger state transitions. This might be a performance problem on quizzes with thousands of attempts.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==New state diagram==&lt;br /&gt;
&lt;br /&gt;
[[Image:Quiz_attempt_states.png]]&lt;br /&gt;
&lt;br /&gt;
At most one attempt can be in either the &#039;&#039;&#039;In progress&#039;&#039;&#039; or &#039;&#039;&#039;Overdue&#039;&#039;&#039; states at any time.&lt;br /&gt;
&lt;br /&gt;
The existing transitions need to be updated:&lt;br /&gt;
* They all need to set the new quiz_attempt.state column as part of What happens.&lt;br /&gt;
* The transition Submit all and finish can now also go from &#039;&#039;&#039;Overdue&#039;&#039;&#039; to &#039;&#039;&#039;Finished&#039;&#039;&#039;.&lt;br /&gt;
* When time runs out as a student is working on their quiz attempt, this should no longer trigger an automatic Submit all and finish. Instead it should trigger an automatic Time expires.&lt;br /&gt;
&lt;br /&gt;
The new transitions are:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Time expires===&lt;br /&gt;
&lt;br /&gt;
Goes from: In progress&lt;br /&gt;
&lt;br /&gt;
Goes to: Overdue&lt;br /&gt;
&lt;br /&gt;
Allowed when: Time expires, either due to the time-limit, the close date, or some other custom access rule; or because the teacher has edited the time limit and/or close date and shortened them; and when the overdue strategy is &amp;quot;Allow a grace period to submit, but not change any responses&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
How it is done: Detected automatically by the Moodle code, either because&lt;br /&gt;
* time has passed;&lt;br /&gt;
* the teacher has edited the quiz settings or overrides to shorten the time limit and/or close date; or&lt;br /&gt;
* triggered by the countdown timer JavaScript, in which case this will trigger a POST to processattempt.php.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# quiz_attempt.state is updated&lt;br /&gt;
# quiz_attempt_overdue event is raised. (The quiz will use this itself to send a warning message to the student, if that is enabled.)&lt;br /&gt;
# If the student is currently working on the quiz, they are redirected to the summary.php page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Give up===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;(not sure that is the best name)&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Goes from: Overdue / In progress&lt;br /&gt;
&lt;br /&gt;
Goes to: Abandoned&lt;br /&gt;
&lt;br /&gt;
Allowed when: Time expires, and the overdue strategy is &amp;quot;That&#039;s it. Tough luck!&amp;quot;; or the grace period expires when an attempt is in the &#039;&#039;&#039;Overdue&#039;&#039;&#039; state.&lt;br /&gt;
&lt;br /&gt;
How it is done: Detected automatically by the Moodle code, either because&lt;br /&gt;
* time has passed;&lt;br /&gt;
* the teacher has edited the quiz settings or overrides to shorten the time limit, close date and/or grace period; or&lt;br /&gt;
* triggered by the countdown timer JavaScript, in which case this will trigger a POST to processattempt.php; or&lt;br /&gt;
* if we decide to allow it, the student clicks a &#039;Give up button&#039;, perhaps on the summary page.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# quiz_attempt.state is updated&lt;br /&gt;
# quiz_attempt_abandoned event is raised. (For completeness. I don&#039;t foresee a use for this at the moment.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Time limit extended===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;This shows the kind of tricky thing that can happen. We have to consider what happens if the teacher edits the quiz settings to extend the time limit when an attempt has already been marked overdue.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Goes from: Overdue&lt;br /&gt;
&lt;br /&gt;
Goes to: In progress&lt;br /&gt;
&lt;br /&gt;
Allowed when: The teacher edits the quiz settings or the overrides and extends the time limit.&lt;br /&gt;
&lt;br /&gt;
How it is done: Detected automatically by the Moodle code.&lt;br /&gt;
&lt;br /&gt;
What happens:&lt;br /&gt;
# quiz_attempt.state is updated&lt;br /&gt;
# quiz_attempt_restarted event is raised. (For completeness. I don&#039;t foresee a use for this at the moment.)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What can be accessed when==&lt;br /&gt;
&lt;br /&gt;
For an &#039;&#039;&#039;In progress&#039;&#039;&#039;&#039; attempt: The student can access attempt.php and summary.php; the teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
For an &#039;&#039;&#039;Overdue&#039;&#039;&#039;&#039; attempt: The student can access review.php and summary.php; the teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
For a &#039;&#039;&#039;Finished&#039;&#039;&#039;&#039; attempt: The student and teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
For an &#039;&#039;&#039;Abandoned&#039;&#039;&#039;&#039; attempt: The student and teacher can access review.php.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Summary of changes==&lt;br /&gt;
&lt;br /&gt;
===Database changes===&lt;br /&gt;
&lt;br /&gt;
* New column quiz.overduehandling (char) to store which strategy we will use for overdue attempts.&lt;br /&gt;
* New column quiz.graceperiod (int) to store the time an attempt is allowed to remain in the &#039;&#039;&#039;Overdue&#039;&#039;&#039; state.&lt;br /&gt;
* New column quiz_attempt.state (char) to explicitly store the attempt state.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===New capability===&lt;br /&gt;
&lt;br /&gt;
* mod/quiz:emailwarnoverdue to control overdue warning messages.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===UI changes===&lt;br /&gt;
&lt;br /&gt;
* New fields &#039;When time expires&#039; and &#039;Grace period&#039; on the quiz settings form, with corresponding admin settings.&lt;br /&gt;
* Do we need even more columns of &#039;review options&#039; on the quiz settings form? (For example for &#039;&#039;&#039;Overdue&#039;&#039;&#039; and &#039;&#039;&#039;Abandoned&#039;&#039;&#039; attempts.) Perhaps it is time to move these settings to a separate page?&lt;br /&gt;
* Information about the grace period may need to be displayed on the quiz settings page, or on the summary page for overdue attempts.&lt;br /&gt;
* List of attempts on the view.php page needs to indicate the state of attempts.&lt;br /&gt;
* review.php page needs to indicate the attempt state.&lt;br /&gt;
* Display attempt state in the quiz reports where appropriate.&lt;br /&gt;
&lt;br /&gt;
==Rough work break-down==&lt;br /&gt;
&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; New quiz.overduehandling, quiz.graceperiod and quiz_attempt.state DB columns definition, upgrade code, backup &amp;amp; restore.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Overdue handling and Grace period setting on quiz form, with any validation. Verify create / edit works.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Implement back end of the three new transitions.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Code where attempts are loaded to identify attempts in the wrong state and trigger a transition if necessary.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Catch the quiz_attempt_overdue event and send an email.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Make attempt_state clear on the view page list of past attempts.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Update logic for the &#039;Start attempt button&#039;, and in startattempt.php so that for overdue attempts users are redirected to the summary page.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Update summary page to display appropriate information about overdue attempts.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Update processattempts.php so that it correctly handles one single submission after an attempt becomes overdue, and, for overdue attempts, will only redirect to the summary page.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Display the attempt state on the review page.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Add the attempt state to the overview and responses quiz reports (this will actually be a change in the base class).&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Add new options to the attempt and overview reports to filter the report by attempt state. (We can probably usefully refactor the settings forms and preferences handling to extract a base class.)&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Out of scope&amp;lt;/span&amp;gt; While we are working here, we should really update these two reports to use the Moodle 2.x enrolment SQL, instead of get_users_by_capability.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Change the statistics report to analyse attempts with state = finished, rather than timefinish &amp;lt;&amp;gt; 0.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Cron to detect attempts in the wrong state and trigger state transitions.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Review all remaining occurrences of -&amp;gt;timefinish in the quiz code.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:green&amp;quot;&amp;gt;Done!&amp;lt;/span&amp;gt; Check the quiz results block - no changes required.&lt;br /&gt;
# &amp;lt;span style=&amp;quot;color:red&amp;quot;&amp;gt;Out of scope&amp;lt;/span&amp;gt; - the official work-around is: &amp;quot;Don&#039;t do that&amp;quot;, at least for now - Deal with what happens when the teacher edits the quiz settings - which might change the times or the policies. Work out what to update.&lt;br /&gt;
&lt;br /&gt;
== Test script==&lt;br /&gt;
&lt;br /&gt;
The 3 examples at http://moodle.org/mod/forum/discuss.php?d=188534 are a good starting point. They just need to be elaborated.&lt;br /&gt;
&lt;br /&gt;
==Hypothetical other transitions==&lt;br /&gt;
&lt;br /&gt;
The following state-transitions can also be conceived, and could be implemented in the future, but they are out-of-scope for this proposal.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Reopen attempt===&lt;br /&gt;
&lt;br /&gt;
Goes from: Finished / Abandoned&lt;br /&gt;
&lt;br /&gt;
Goes to: In progress&lt;br /&gt;
&lt;br /&gt;
Allowed when: Time has not expired, and the current user has the appropriate capability.&lt;br /&gt;
&lt;br /&gt;
(For example, the student accidentally clicked Submit all and finish, and the teacher wants to be nice and undo that for them. Alternatively an attempt has become Abandoned because time ran out, but then the teacher extended the grace period or time limit, and so wants to re-open some attempts. In this case, the transition may go to &#039;&#039;&#039;Overdue&#039;&#039;&#039;, or perhaps that is a different transition, or perhaps the right way to handle that is to first transition to &#039;&#039;&#039;In progress&#039;&#039;&#039; and then transition to &#039;&#039;&#039;Overdue&#039;&#039;&#039;. I think it is clear why this is being considered out-of-scope.)&lt;br /&gt;
&lt;br /&gt;
How it is done: Probably clicking a button on the review page or in the quiz reports. This would probably be a POST to a new reopenattempt.php&lt;br /&gt;
&lt;br /&gt;
What happens: This is a bit tricky because lots of complex stuff happens on Submit all and finish that now needs to be undone, but I think a possible approach is to delete any question_attempts_steps added by the finish action (and any that follow them) and then use a regrade of the attempt to reset everything else.&lt;br /&gt;
&lt;br /&gt;
Actually, it is much easier to re-open an &#039;&#039;&#039;Abandoned&#039;&#039;&#039; attempt than a &#039;&#039;&#039;Finished&#039;&#039;&#039; one. Perhaps we should consider them two different transitions, or perhaps reopening an &#039;&#039;&#039;Abandoned&#039;&#039;&#039; attempt can be treated the same as Time limit extended.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Transition: Count this anyway===&lt;br /&gt;
&lt;br /&gt;
Goes from: Abandoned&lt;br /&gt;
&lt;br /&gt;
Goes to: Submitted&lt;br /&gt;
&lt;br /&gt;
Allowed when: The current user has the appropriate capability.&lt;br /&gt;
&lt;br /&gt;
(For example a teacher decides that even though the student abandoned their attempt, it should be counted anyway.)&lt;br /&gt;
&lt;br /&gt;
How it is done: Probably clicking a button on the review page or in the quiz reports. This would probably be a POST either to processattempt.php with extra arguments, or to a new script.&lt;br /&gt;
&lt;br /&gt;
What happens: Probably very similar to Submit all and finish.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* MDL-3030 Late quiz attempts should be closed automatically&lt;br /&gt;
* MDL-4309 Ability for late quizzes (with penalty)&lt;br /&gt;
* MDL-35322 Student didn&#039;t submit quiz, status is Never Submitted, version 2.3.1&lt;br /&gt;
* [[Quiz]] developer documentation&lt;br /&gt;
* Draft user documentation: [[Quiz time controls on attempts]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=States_of_a_quiz_attempt&amp;diff=55882</id>
		<title>States of a quiz attempt</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=States_of_a_quiz_attempt&amp;diff=55882"/>
		<updated>2019-04-04T08:11:34Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Relevant tracker issues */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{obsolete}}&lt;br /&gt;
See [[Better handling of overdue quiz attempts]] for more current information.&lt;br /&gt;
&lt;br /&gt;
This page relates to the problem of the following scenario:&lt;br /&gt;
# Student starts an attempt at a timed quiz.&lt;br /&gt;
# Student logs out and goes away.&lt;br /&gt;
# Quiz time limit expires.&lt;br /&gt;
# Student (or teacher) comes back. They now cannot continue (or review, or complete) the quiz attempt. They are stuck.&lt;br /&gt;
::That&#039;s not what actually happens. Actually on 4 student see a button to continue his attempt. He press it and goes to the attempt, which is instantly submitted, and he get returned to quiz intro. He could then start a new attempt ... if there is no time delay between attempts. If there is he is stuck.--[[User:Oleg Sychev|Oleg Sychev]] 19:55, 24 November 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
Different people have different desires for how this is handled. The aim of this page is to collect together all the things that different people might want, so we can try to design a solution that makes everyone happy.&lt;br /&gt;
&lt;br /&gt;
Currently this page is just a random dump of things Tim remembered, please feel free to add to, or edit it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What currently happens==&lt;br /&gt;
&lt;br /&gt;
===The states a quiz attempt can be in===&lt;br /&gt;
&lt;br /&gt;
* {before the attempt is started}. Not sure if this really exists. Before the attempt has been started, it does not exist!&lt;br /&gt;
* During the quiz attempt (Quiz attempt open). This is distinguished by $attempt-&amp;gt;timefinish being 0.&lt;br /&gt;
* After the attempt is finished. This is distinguished by $attempt-&amp;gt;timefinish being non-zero.&lt;br /&gt;
&lt;br /&gt;
===Behaviour===&lt;br /&gt;
&lt;br /&gt;
* A user can have at most one quiz attempt open at any time.&lt;br /&gt;
* If the user is attempting the quiz when the time expires, and if they have JavaScript on, then the quiz is automatically submitted for them.&lt;br /&gt;
* If the student is not attempting the quiz when the time expires, then their attempt is not submitted, and neither the student nor the teacher can submit it.&lt;br /&gt;
  Actually the attempt will be graded 0, but individual questions may be regraded if page was saved. &lt;br /&gt;
  Teachers could use it to calculate attempt grade manually, but they really don&#039;t like it.--[[User:Oleg Sychev|Oleg Sychev]] 19:55, 24 November 2009 (UTC)&lt;br /&gt;
* Time can expire either because of $quiz-&amp;gt;timelimit, or $quiz-&amp;gt;timeclose.&lt;br /&gt;
* There is a capability mod/quiz:ingoretimelimit for accessibility reasons. This causes $quiz-&amp;gt;timelimit, but not $quiz-&amp;gt;timeclose, to be ignored.&lt;br /&gt;
* After the attempt is submitted, students may, or may not be able to review, depending on the quiz review settings and whether $quiz-&amp;gt;timeclose has passed.&lt;br /&gt;
* In addition to the only one open attempt rule, there may also be a delay between the end of one quiz attempt and the start of the next ($quiz-&amp;gt;delay1/2).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==What we would like to happen==&lt;br /&gt;
&lt;br /&gt;
===The states we need to distinguish===&lt;br /&gt;
&lt;br /&gt;
* {before the attempt is started}&lt;br /&gt;
* Quiz attempt open, time has not expired.&lt;br /&gt;
* Quiz attempt open, time has expired.&lt;br /&gt;
* Quiz attempt submitted, some questions need manual grading.&lt;br /&gt;
* Quiz attempt submitted, all questions graded.&lt;br /&gt;
  Actually these states makes quiz time delay more complicated. &lt;br /&gt;
  The question is what state it should use as an end of previous attempt? &lt;br /&gt;
  It should be submission for quizzes without time limit.&lt;br /&gt;
  But for quizzes with time limit it should be min(time expiration,  submission) otherwise we still may get &lt;br /&gt;
  problem with time delay mentioned above.--[[User:Oleg Sychev|Oleg Sychev]] 19:55, 24 November 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
Might we also want/need to distinguish the states &#039;results not visible yet&#039;, and &#039;results released to student&#039;, for a submitted quiz. These two are orthogonal to whether any questions need manual grading, so that actually leads to four sub-states under submitted.&lt;br /&gt;
&lt;br /&gt;
===Behaviour===&lt;br /&gt;
&lt;br /&gt;
* Teacher should have the option to submit an attempt when the student forgot.&lt;br /&gt;
* Student should have the option to submit an attempt late (but not answer any more questions) when they forgot. Probably the best way to do this is that after time has expired, if the student is still allowed to Submit all and finish, they can only go to the attempt summary page (in Moodle 2.0) and click the submit button.&lt;br /&gt;
* Some people like the current behaviour: the student must submit on time, and if they don&#039;t they don&#039;t get a grade, and it is tough luck. Therefore, if students are allowed to submit the quiz late, there should be a time limit for how much extra time they have in which to do so (which can be anything from 0 to infinity).&lt;br /&gt;
* There should be an option which, at the moment when time expires on an attempt, send an email to the student reminding them that they have not submitted it, and explaining to them how to do so, and how long in which they have to do so.&lt;br /&gt;
* Alternatively, the quiz may have an option set to automatically submit any quiz attempt the moment time has expired.&lt;br /&gt;
* May want an option where, if the student is allowed to submit late, we do process any updated answers, but a penalty is applied to their score.&lt;br /&gt;
* May want an option for a teacher to un-submit a quiz attempt, for those situations where a student has (claims to have) clicked Submit all and Finish too early, by mistake.&lt;br /&gt;
* Teachers can delete any quiz attempt (open or submitted) at any time (&#039;&#039;this has been implemented for a long time&#039;&#039;)&lt;br /&gt;
* Giving teacher the ability to decide, that particular student in particular attempt could bypass time delay (without deleting previous attempt) will resolve a great deal of the problems. (&#039;&#039;this is implemented in Moodle 2.0&#039;&#039;)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Other ideas===&lt;br /&gt;
&lt;br /&gt;
* Some people may want to count un-submitted attempts if quiz has a limit on a number of attempts, other may want to exclude them.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; This is not really possible, given the assumption the quiz has that there is at most one open attempt, which can either be submitted or deleted, and once it is submitted, it counts. I also don&#039;t really see the point of this. If you are being that flexible, why have a limit on the number of attempts at all? &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* May want an option for a teacher to extend time limit for particular attempt (if, for example, computer hangs during the attempt, or the student press submit near the finish and wait more than 60 seconds)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; This is, as opposed to extending it for all attempts for a particular student. This would be a lot of work to implement, and only occasionally useful. For now, I think it is sufficient to have the option to change the time limit for one student. You can always extend it until they have submitted that one attempt, and then change it back. &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* (I don&#039;t know whether it really possible, but it&#039;s a very good option to have) Save current attempt state with responses in a browser window if submitting request on server failed. Sometimes server go down during important attempts (exams and so no), that&#039;s quite bad for timed quizzes. At least we could send AJAX request to the server before submitting to verify it still working (should work in couple with teacher-defined time limit extension mentioned above to prevent abuse).&lt;br /&gt;
&lt;br /&gt;
&#039;&#039; This is not possible. &#039;&#039;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
* ... please add more ideas here ...&lt;br /&gt;
&lt;br /&gt;
===Changes to the code===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Note that this builds on top of Moodle 2.0. If you don&#039;t know what things like the summary page are, or how the quiz reports work in the latest version, this may not make any sense.&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* New capability mod/quiz:submitlateattempt - can apply to students, and/or teachers, but with slightly different meaning. (Teacher here is probably defined by mod/quiz:grade, or mod/quiz:viewreports. Or perhaps it is clearly to have separate capabilities mod/quiz:submitmylateattempt and mod/quiz:submitanylateattempt.) Or perhaps rather than a capability, a quiz setting saying how much extra time students have after their attempt becomes overdue, to go in and submit it.&lt;br /&gt;
&lt;br /&gt;
* If a student has mod/quiz:submitlateattempt, and/or if they are still within the extra time allowed, then they can get at overdue quiz attempts, but they can only go to the summary page in order to click the Submit all and finish button.&lt;br /&gt;
&lt;br /&gt;
* For teachers with mod/quiz:submitlateattempt, there will be a new button in the quiz reports (next to delete attempts and regrade attempts) to submit any overdue quiz attempts that have been selected using the check-boxes.&lt;br /&gt;
&lt;br /&gt;
* New database column quiz_attempt.state, to make the current state of each attempt clear. (Not sure if this is really necessary.)&lt;br /&gt;
&lt;br /&gt;
* Code on cron, or when the attempt is accessed, to update the attempt state if, for example, time has expired since it was last changed.&lt;br /&gt;
&lt;br /&gt;
* A quiz option, and code on cron, to automatically submit overdue quiz attempts if that is what the teacher wants.&lt;br /&gt;
&lt;br /&gt;
* A quiz option, and code on cron, to email a student when an attempt becomes overdue, telling them how long the still have to submit it, and how to do so.&lt;br /&gt;
&lt;br /&gt;
* Possibly new column quiz_attempt.finishedby, to record the userid of the user who submitted the attempt, so we know if the teacher has submitted a later attempt for the student. Could be NULL, if late attempts are submitted automatically.&lt;br /&gt;
&lt;br /&gt;
* Code in the question engine to correctly process incomplete attempts when an overdue attempt is submitted.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
===Discussion===&lt;br /&gt;
&lt;br /&gt;
* Please discuss this in [http://moodle.org/mod/forum/discuss.php?d=138660 this Quiz forum thread].&lt;br /&gt;
&lt;br /&gt;
===Relevant tracker issues===&lt;br /&gt;
&lt;br /&gt;
* MDL-3030 Late quiz attempts should be closed automatically&lt;br /&gt;
* MDL-3452 Use saved answers when marking late submissions&lt;br /&gt;
* MDL-4309 Ability for late quizzes (with penalty)&lt;br /&gt;
* MDL-20956 Student can&#039;t start new attempt if a quiz has timle limit between attempts and time limit for a quiz, and he doesn&#039;t submit previous attempt closing browser window instead&lt;br /&gt;
* MDL-35322 Student didn&#039;t submit quiz, status is Never Submitted, version 2.3.1&lt;br /&gt;
* ... please add other relevant tracker issues here.&lt;br /&gt;
&lt;br /&gt;
===See also===&lt;br /&gt;
&lt;br /&gt;
* [[Better handling of overdue quiz attempts]]&lt;br /&gt;
* [[Goals_of_an_online_assessment_system|Goals of an online assessment system]]&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=118343 Closing unfinished attempts - possible solution for 1.9]&lt;br /&gt;
* [https://docs.moodle.org/23/en/User_talk:John_Rich Moodle Documents]&lt;br /&gt;
&lt;br /&gt;
[[Category:Quiz]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Custom_fields_API&amp;diff=55865</id>
		<title>Custom fields API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Custom_fields_API&amp;diff=55865"/>
		<updated>2019-04-03T11:44:04Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Add See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.7}}&lt;br /&gt;
&lt;br /&gt;
== Custom fields API overview ==&lt;br /&gt;
&lt;br /&gt;
Custom fields API was added in Moodle 3.7. It allows to configure custom fields that can be added to various contexts. Each &#039;&#039;&#039;component&#039;&#039;&#039; (or plugin) that wants to use custom fields can define several &#039;&#039;&#039;areas&#039;&#039;&#039;. For example, &#039;core_course&#039; component defines an area &#039;course&#039; that allows to add custom fields to the courses, the same component can define another area &#039;coursecat&#039; that will allow to add custom fields to the course categories. Inside each area the component/plugin can decide whether to use or not to use &#039;&#039;&#039;itemid&#039;&#039;&#039;. For example, course custom fields are the same throughout the system and they don&#039;t use itemid (it is always 0). But there could be an activity module that would want to configure different custom fields for each individual instance of module, then this module would use the module id as the itemid, as in ([https://github.com/marinaglancy/moodle-mod_surveybuilder example]). This would allow to create modules similar to mod_data and mod_feedback where each instance has it&#039;s own set of fields.&lt;br /&gt;
&lt;br /&gt;
New plugin type &amp;quot;customfield&amp;quot; was also added as part of the Custom fields API. Additional types of custom fields can be installed into /customfield/field/ .&lt;br /&gt;
&lt;br /&gt;
== How to use custom fields ==&lt;br /&gt;
&lt;br /&gt;
Component/plugin that uses custom fields must define a &#039;&#039;&#039;handler class&#039;&#039;&#039; for each area and a &#039;&#039;&#039;configuration page&#039;&#039;&#039;. Handler class must be called &#039;&#039;&#039;&amp;lt;PLUGINNAME&amp;gt;/customfield/&amp;lt;AREA&amp;gt;_handler&#039;&#039;&#039; and be placed in autoloaded location (&amp;lt;PLUGINDIR&amp;gt;/classes/customfield/&amp;lt;AREA&amp;gt;_handler.php . This class must extend &#039;&#039;&#039;\core_customfield\handler&#039;&#039;&#039; . Configuration page may be located anywhere. For course custom fields configuration the admin settings page is used [https://github.com/moodle/moodle/blob/master/course/customfield.php /course/customfield.php]. If the area uses itemid this page should take itemid as a parameter.&lt;br /&gt;
&lt;br /&gt;
Handler has protected constructor, to get a handler call create() method. Some areas may choose to return a singleton here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$handler = HANDLERCLASS::create($itemid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Configuration page contents will be:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;core_customfield&#039;);&lt;br /&gt;
$outputpage = new \core_customfield\output\management($handler);&lt;br /&gt;
echo $output-&amp;gt;render($outputpage);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Handler must implement all abstract methods (calculate configuration or instance context, check permissions to configure, view or edit) and also may choose to overwrite:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
handler::uses_categories()&lt;br /&gt;
handler::generate_category_name()&lt;br /&gt;
handler::config_form_definition() // For example, the course_handler adds &amp;quot;locked&amp;quot; and &amp;quot;visibility&amp;quot; settings that control who can edit or view the particular field.&lt;br /&gt;
handler::setup_edit_page() // Sets page context/url/breadcrumb for the customfield/edit.php page, in some cases it must be overridden.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Add custom fields to the instance edit form ===&lt;br /&gt;
&lt;br /&gt;
Custom fields are added to the &#039;&#039;&#039;instances&#039;&#039;&#039;. For example, course custom fields are added to the courses, so courseid is the instanceid. In the example of [https://github.com/marinaglancy/moodle-mod_surveybuilder mod_surveybuilder] we use $USER-&amp;gt;id as the instanceid (which means that in this example one user can fill the survey in one module only once). In each case of using custom fields there should be a clear concept of an &#039;&#039;&#039;instance&#039;&#039;&#039;. Instanceid is required to save the data but it may be empty when we render the instance edit form (for example, the course is not yet created).&lt;br /&gt;
&lt;br /&gt;
Developer must add custom fields callbacks to the instance edit form. If the instance is &amp;quot;made up&amp;quot; (like in mod_surveybuilder), a new form has to be created with &#039;id&#039; field in it that will refer to the instanceid.&lt;br /&gt;
&lt;br /&gt;
The following callbacks should be used in form definition, definition_after_data, validation and after form submission:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$hander-&amp;gt;instance_form_definition()&lt;br /&gt;
$hander-&amp;gt;instance_form_before_set_data()&lt;br /&gt;
$hander-&amp;gt;instance_form_definition_after_data()&lt;br /&gt;
$hander-&amp;gt;instance_form_validation()&lt;br /&gt;
$hander-&amp;gt;instance_form_save()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
On deletion of an instance or on deletion of the whole item call:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$hander-&amp;gt;delete_instance()&lt;br /&gt;
$hander-&amp;gt;delete_all()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Retrieving instances custom fields ===&lt;br /&gt;
&lt;br /&gt;
How custom fields are used depends entirely on the situation. The following handler methods will help you to retrieve custom fields values for the given instance(s):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$handler-&amp;gt;export_instance_data()&lt;br /&gt;
$handler-&amp;gt;export_instance_data_object()&lt;br /&gt;
$handler-&amp;gt;display_custom_fields_data()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Additional methods for advanced usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$handler-&amp;gt;get_instance_data()&lt;br /&gt;
$handler-&amp;gt;get_instances_data()&lt;br /&gt;
$handler-&amp;gt;get_instance_data_for_backup()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Method restore_instance_data_from_backup() exists in the handler class but not implemented&lt;br /&gt;
&lt;br /&gt;
To retrieve the list of custom fields used in the given component/area/itemid you can use:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$handler-&amp;gt;get_categories_with_fields()&lt;br /&gt;
$handler-&amp;gt;get_fields()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
List of fields is cached in the handler and these two functions can be called multiple times.&lt;br /&gt;
&lt;br /&gt;
=== Privacy API ===&lt;br /&gt;
&lt;br /&gt;
Custom fields API does not export or delete any data because it does not know how custom fields are used, what data is considered user data and if it is considered private or shared data. &lt;br /&gt;
&lt;br /&gt;
Plugins that store user information in custom fields should link subsystem in their get_metadata:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$collection-&amp;gt;link_subsystem(&#039;core_customfield&#039;, &#039;privacy:metadata:customfieldpurpose&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And they can use the following methods in the export/delete functions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
use core_customfield\privacy\provider as customfield_provider;&lt;br /&gt;
&lt;br /&gt;
customfield_provider::get_customfields_data_contexts()&lt;br /&gt;
customfield_provider::export_customfields_data()&lt;br /&gt;
customfield_provider::delete_customfields_data()&lt;br /&gt;
customfield_provider::delete_customfields_data_for_context()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
In case when custom fields configuration is considered to be user data (configuration means the definition of the fields, not the instance data), there are also couple of methods to help with privacy API implementations:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
customfield_provider::get_customfields_configuration_contexts()&lt;br /&gt;
customfield_provider::delete_customfields_configuration()&lt;br /&gt;
customfield_provider::delete_customfields_configuration_for_context()&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Export of configuration was not yet implemented at the time of writing this because of difficult implementation and very unclear use case. If it is needed please feel free to contribute to Moodle.&lt;br /&gt;
&lt;br /&gt;
== Custom fields plugins ==&lt;br /&gt;
&lt;br /&gt;
Custom fields plugin type was added to allow implement different types of custom fields (somehow similar to user profile fields plugin type). Plugins are located in &#039;&#039;&#039;/customfield/field/&#039;&#039;&#039; and the full frankenstyle name of the plugins start with &#039;&#039;&#039;customfield_&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Except for common [[Plugin files]] and tests the following classes must be present in customfield plugins (in respective autoloaded locations):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace customfield_&amp;lt;PLUGINNAME&amp;gt;;&lt;br /&gt;
class field_controller extends \core_customfield\field_controller;&lt;br /&gt;
class data_controller extends \core_customfield\data_controller;&lt;br /&gt;
&lt;br /&gt;
namespace customfield_&amp;lt;PLUGINNAME&amp;gt;\privacy;&lt;br /&gt;
class provider implements \core_privacy\local\metadata\null_provider, \core_customfield\privacy\customfield_provider;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
MDL-64626 - Custom fields API (Moodle 3.7+) implementations and improvements&lt;br /&gt;
&lt;br /&gt;
MDL-57898 - Add custom field types plugin and course custom fields functionality&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meeting_January_2019&amp;diff=55377</id>
		<title>Developer meeting January 2019</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meeting_January_2019&amp;diff=55377"/>
		<updated>2019-01-09T07:17:03Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Add custom reporting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Developer meetings]] &amp;gt; January 2019 meeting notes&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Time&lt;br /&gt;
| 13:00 UTC on Thursday, 10 January 2019&lt;br /&gt;
|-&lt;br /&gt;
| Join URL: &lt;br /&gt;
| https://moodle.zoom.us/j/259887936&lt;br /&gt;
|-&lt;br /&gt;
| Meeting recording (including searchable, indexed transcript and chat log)&lt;br /&gt;
| TBD &lt;br /&gt;
|-&lt;br /&gt;
| Meeting Minutes&lt;br /&gt;
| https://etherpad.net/p/MoodleDevCommunity-01-19&lt;br /&gt;
|-&lt;br /&gt;
| Discussion&lt;br /&gt;
| [https://moodle.org/mod/forum/discuss.php?d=378355 Discussion thread at moodle.org]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Proposed Agenda ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This is an editable page. Please propose items you would like to present on (or request) here!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Custom reporting in Moodle - is there any progress?&lt;br /&gt;
# Are there any plans to upgrade the Configurable Reports plugin? An official comment from Moodle or Juan would help calm the nerves.&lt;br /&gt;
# Status of the MUA customizable report builder proposal?&lt;br /&gt;
&lt;br /&gt;
== Minutes ==&lt;br /&gt;
&lt;br /&gt;
Minutes will be captured via Etherpad at https://etherpad.net/p/MoodleDevCommunity-01-19.&lt;br /&gt;
----&lt;br /&gt;
Please feel encouraged to raise topics you would like to present / discuss during these meetings. Contact [https://moodle.org/user/profile.php?id=1413178 Elizabeth Dalton] for details.&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Developer_meeting_January_2019&amp;diff=55376</id>
		<title>Developer meeting January 2019</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Developer_meeting_January_2019&amp;diff=55376"/>
		<updated>2019-01-09T07:14:06Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Add custom reporting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Developer meetings]] &amp;gt; January 2019 meeting notes&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| Time&lt;br /&gt;
| 13:00 UTC on Thursday, 10 January 2019&lt;br /&gt;
|-&lt;br /&gt;
| Join URL: &lt;br /&gt;
| https://moodle.zoom.us/j/259887936&lt;br /&gt;
|-&lt;br /&gt;
| Meeting recording (including searchable, indexed transcript and chat log)&lt;br /&gt;
| TBD &lt;br /&gt;
|-&lt;br /&gt;
| Meeting Minutes&lt;br /&gt;
| https://etherpad.net/p/MoodleDevCommunity-01-19&lt;br /&gt;
|-&lt;br /&gt;
| Discussion&lt;br /&gt;
| [https://moodle.org/mod/forum/discuss.php?d=378355 Discussion thread at moodle.org]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Proposed Agenda ==&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;This is an editable page. Please propose items you would like to present on (or request) here!&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
* Custom reporting in Moodle - is there any progress?&lt;br /&gt;
# Are there any plans to upgrade the Configurable Reports plugin?&lt;br /&gt;
# Status of the MUA customizable report builder proposal?&lt;br /&gt;
&lt;br /&gt;
== Minutes ==&lt;br /&gt;
&lt;br /&gt;
Minutes will be captured via Etherpad at https://etherpad.net/p/MoodleDevCommunity-01-19.&lt;br /&gt;
----&lt;br /&gt;
Please feel encouraged to raise topics you would like to present / discuss during these meetings. Contact [https://moodle.org/user/profile.php?id=1413178 Elizabeth Dalton] for details.&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AJAX&amp;diff=55341</id>
		<title>AJAX</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AJAX&amp;diff=55341"/>
		<updated>2019-01-03T11:01:56Z</updated>

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

		<summary type="html">&lt;p&gt;Libertymoodle: /* memcached on Windows */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Does anybody know whether as of today neither MSSQL nor SQLSRV are still available under php7 ? [[User:German Valero|German Valero]] ([[User talk:German Valero|talk]])&lt;br /&gt;
: Hi German, 99.99% sure mssql won&#039;t be ever back, after a voting it [http://php.net/manual/en/intro.mssql.php was removed] from php. And, last time I looked for [https://github.com/Azure/msphpsql/tree/PHP-7.0 sqlsrv] it was not ready yet. Maybe worth updating [[Moodle and PHP7#Can_I_use_PHP7_yet.3F|the &amp;quot;can I use it&amp;quot;]] section. --[[User:Eloy Lafuente (stronk7)|Eloy Lafuente (stronk7)]] ([[User talk:Eloy Lafuente (stronk7)|talk]])&lt;br /&gt;
&lt;br /&gt;
Is it good or bad to use PHP7 when installing an Ubuntu server (either local for testing or a production server) ? &lt;br /&gt;
&lt;br /&gt;
Shall we change [https://docs.moodle.org/31/en/Step-by-step_Installation_Guide_for_Ubuntu#Why_we_prefer_.28or_don.27t_prefer.29_Ubuntu_16.04_over_Ubuntu_14.04 https://docs.moodle.org/31/en/Step-by-step_Installation_Guide_for_Ubuntu#Why_we_prefer_.28or_don.27t_prefer.29_Ubuntu_16.04_over_Ubuntu_14.04]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
What are the options for running Memcached on Windows Server hosted Moodle sites? Yes? No? Do it? Don&#039;t do it?&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 08:24, 18 December 2018 (UTC)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Moodle_3.5_release_notes&amp;diff=54692</id>
		<title>Moodle 3.5 release notes</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Moodle_3.5_release_notes&amp;diff=54692"/>
		<updated>2018-09-04T09:58:05Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Added 3.5.1 release notes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Releases]] &amp;gt; {{FULLPAGENAME}}&lt;br /&gt;
 &lt;br /&gt;
Release date: 17 May 2018&lt;br /&gt;
&lt;br /&gt;
Here is [https://tracker.moodle.org/secure/IssueNavigator!executeAdvanced.jspa?jqlQuery=project+%3D+mdl+AND+resolution+%3D+fixed+AND+fixVersion+in+%28%223.5%22%29+ORDER+BY+priority+DESC&amp;amp;runQuery=true&amp;amp;clear=true the full list of fixed issues in 3.5].&lt;br /&gt;
&lt;br /&gt;
See our [https://docs.moodle.org/35/en/New_features New Features page] for a more user-friendly introduction to Moodle 3.5 with screenshots.&lt;br /&gt;
&lt;br /&gt;
If you are upgrading from previous version, make sure you read the [https://docs.moodle.org/35/en/Upgrading Upgrading] documentation.&lt;br /&gt;
&lt;br /&gt;
==Server requirements==&lt;br /&gt;
&lt;br /&gt;
These are just the minimum supported versions. We recommend keeping all of your software and operating systems up-to-date.&lt;br /&gt;
&lt;br /&gt;
* Moodle upgrade:  Moodle 3.1 or later&lt;br /&gt;
* PHP version: minimum PHP 7.0.0 &#039;&#039;Note: minimum PHP version has increased since Moodle 3.3&#039;&#039;. PHP 7.1.x and 7.2.x are supported too. PHP 7.x could have some [https://docs.moodle.org/dev/Moodle_and_PHP7#Can_I_use_PHP7_yet.3F engine limitations]. &lt;br /&gt;
* PHP extension &#039;&#039;&#039;intl&#039;&#039;&#039; is required since Moodle 3.4 (it was recommended in 2.0 onwards) &lt;br /&gt;
* (Recommendation only) If you use MySQL or MariaDB, make sure your database supports full UTF-8 (utf8mb4) if you install a new instance of Moodle. CLI script may be used to convert to utf8mb4 if you&#039;re upgrading. You may choose to keep using &#039;utf8_*&#039;, but then a warning will show that the database isn&#039;t using full UTF-8 support and suggest moving to &#039;utf8mb4_unicode_ci&#039;. See [[:en:MySQL full unicode support|MySQL full unicode support]] for details. If you do enable utf8mb4 you *must* use the Barracuda file format. &lt;br /&gt;
&lt;br /&gt;
=== Database requirements ===&lt;br /&gt;
&lt;br /&gt;
Moodle supports the following database servers. Again, version numbers are just the minimum supported version. We recommend running the latest stable version of any software.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Database&lt;br /&gt;
! Minimum version&lt;br /&gt;
! Recommended&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.postgresql.org/ PostgreSQL]&lt;br /&gt;
| 9.3&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.mysql.com/ MySQL]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [https://mariadb.org/ MariaDB]&lt;br /&gt;
| 5.5.31&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.microsoft.com/en-us/server-cloud/products/sql-server/ Microsoft SQL Server]&lt;br /&gt;
| 2008&lt;br /&gt;
| Latest&lt;br /&gt;
|-&lt;br /&gt;
| [http://www.oracle.com/us/products/database/overview/index.html Oracle Database]&lt;br /&gt;
| 10.2&lt;br /&gt;
| Latest&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==Client requirements==&lt;br /&gt;
&lt;br /&gt;
=== Browser support ===&lt;br /&gt;
Moodle is compatible with any standards compliant web browser. We regularly test Moodle with the following browsers:&lt;br /&gt;
&lt;br /&gt;
Desktop:&lt;br /&gt;
* Chrome&lt;br /&gt;
* Firefox&lt;br /&gt;
* Safari&lt;br /&gt;
* Edge&lt;br /&gt;
* Internet Explorer&lt;br /&gt;
&lt;br /&gt;
Mobile:&lt;br /&gt;
* MobileSafari&lt;br /&gt;
* Google Chrome&lt;br /&gt;
&lt;br /&gt;
For the best experience and optimum security, we recommend that you keep your browser up to date. https://whatbrowser.org&lt;br /&gt;
&lt;br /&gt;
Note: Legacy browsers with known compatibility issues with Moodle 3.5:&lt;br /&gt;
* Internet Explorer 10 and below&lt;br /&gt;
* Safari 7 and below&lt;br /&gt;
 &lt;br /&gt;
&lt;br /&gt;
==Major features==&lt;br /&gt;
&lt;br /&gt;
===GDPR===&lt;br /&gt;
* &#039;&#039;&#039;MDL-61275 - GDPR Consenting of Minors and Managing, Versioning and Tracking Privacy Policies and User Consents&#039;&#039;&#039;&lt;br /&gt;
* MDL-61292 - A new admin tool to manage policy documents&lt;br /&gt;
* MDL-61423 - Add age and location verification to identify minors&lt;br /&gt;
* MDL-61302 - Workflow to allow users to agree to all policies&lt;br /&gt;
* MDL-61301 - Report of user agreed policies and their versions&lt;br /&gt;
* MDL-61705 - Bulk accept of policies on behalf of users&lt;br /&gt;
* MDL-61864 - Include policy tool in core&lt;br /&gt;
* MDL-62286 - Add policy link to the site footer&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;MDL-61306 - GDPR Data Requests and Data Registry&#039;&#039;&#039;&lt;br /&gt;
* MDL-59718 - A process to send a request to the data protection officer&lt;br /&gt;
* MDL-59720 - Delete personal data when it is no longer required&lt;br /&gt;
* MDL-61307 - Create a new privacy subsystem&lt;br /&gt;
* MDL-61362 - Ability to create data categories and purposes&lt;br /&gt;
* MDL-61486 - Data registry with purpose and retention period&lt;br /&gt;
* MDL-61489 - Report of plugin/components implementing the Privacy API&lt;br /&gt;
* MDL-61499 - Ability to set default purpose and retention periods for context levels&lt;br /&gt;
* MDL-61785 - Ability to review and confirm which expired data can be deleted&lt;br /&gt;
* MDL-61899 - Include data privacy tool in core&lt;br /&gt;
* MDL-61935 - Ability to specify the lawful bases for the collection of personal data&lt;br /&gt;
&lt;br /&gt;
===Question bank tagging improvements===&lt;br /&gt;
* MDL-61066 - Expanded tagging functionality for question bank&lt;br /&gt;
* MDL-61133 - New modal to add/edit/remove tags on questions&lt;br /&gt;
* MDL-61135 - Filter questions by tag&lt;br /&gt;
* MDL-61138 - Show the list of questions in the &#039;Add a random question&#039; dialog&lt;br /&gt;
* MDL-61363 - Ability to add question tags at a course level in the edit question form&lt;br /&gt;
* MDL-61364 - Manage tags at a question and course context level&lt;br /&gt;
* MDL-61380 - Allow filtering/adding random questions by tag for quizzes&lt;br /&gt;
* MDL-61410 - Add import/export support for course level question tags&lt;br /&gt;
* MDL-61444 - New capabilities for tagging questions&lt;br /&gt;
&lt;br /&gt;
===UX: Usability improvements===&lt;br /&gt;
* MDL-62021 - Boost 4.0 Migration&lt;br /&gt;
* MDL-56511 - Update bootstrap 4 to final release&lt;br /&gt;
* MDL-61657 - Add images to the course cards on the dashboard&lt;br /&gt;
&lt;br /&gt;
===LTI Advantage support===&lt;br /&gt;
* MDL-60416 - Add support for LTI Advantage 1.1&lt;br /&gt;
&lt;br /&gt;
===RecordRTC for Atto===&lt;br /&gt;
* MDL-60848 - Implement RecordRTC Atto plugin as core feature&lt;br /&gt;
* MDL-61973 - Update RecordRTC Atto plugin buttons&lt;br /&gt;
&lt;br /&gt;
===Messaging database tables===&lt;br /&gt;
* MDL-61254 - Merge messaging database tables&lt;br /&gt;
* MDL-36941 - Create new tables for messaging&lt;br /&gt;
* MDL-61255 - Ad-hoc task to upgrade messages to merged table &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Other Highlights==&lt;br /&gt;
&lt;br /&gt;
===Global search===&lt;br /&gt;
* MDL-58885 - Add group support&lt;br /&gt;
* MDL-59434 - Content aware searching / alternate results sort orders&lt;br /&gt;
* MDL-60981 - Reindex a single area&lt;br /&gt;
* MDL-61028 - Allow filtering search by user&lt;br /&gt;
* MDL-61256 - Search of section titles, summaries&lt;br /&gt;
&lt;br /&gt;
===Functional changes===&lt;br /&gt;
* MDL-2051 - Inform student whether and how their selected choice will display&lt;br /&gt;
* MDL-32585 - SCORM: option to force new attempts&lt;br /&gt;
* MDL-53226 - Add Moodle DB search engine&lt;br /&gt;
* MDL-55491 - Use cohort as badge criteria&lt;br /&gt;
* MDL-56246 - Add site wide default for grade export: include feedback&lt;br /&gt;
* MDL-59875 - Allow badges as criteria for other badges&lt;br /&gt;
* MDL-60119 - Feedback - Multiple choice (rated) - remove weights from answer&lt;br /&gt;
* MDL-61203 - Allow uploading of profile picture to be used as badge criteria&lt;br /&gt;
* MDL-61601 - Allow cohort themes&lt;br /&gt;
* MDL-61651 - LTI: line item definition within link to return gradable LTI links&lt;br /&gt;
* MDL-60811 - Bulk delete self-registered enrolments on participants page&lt;br /&gt;
* MDL-60682 - Ability to set date/time to nearest minute&lt;br /&gt;
* MDL-60441 - Ability to add a link to glossary entries&lt;br /&gt;
* MDL-58411 - Ability to apply file type restrictions for essay question type&lt;br /&gt;
* MDL-56945 - Add easy return path from PDF grading screen to list of submissions&lt;br /&gt;
* MDL-52811 - Add force language capability to course settings&lt;br /&gt;
* MDL-41090 - Allow teachers to embed files when manually grading questions&lt;br /&gt;
&lt;br /&gt;
===Security issues===&lt;br /&gt;
 &lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=371199 MSA-18-0007] Calculated question type allows remote code execution by Question authors&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=371200 MSA-18-0008] Users can download any file via portfolio assignment caller class&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=371201 MSA-18-0009] Portfolio forum caller class allows a user to download any file&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=371202 MSA-18-0010] User can shift a block from Dashboard to any page&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=371203 MSA-18-0011] User who did not agree to the site policies can see the site homepage as if they had full site access&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=371204 MSA-18-0012] Portfolio script allows instantiation of class chosen by user&lt;br /&gt;
&lt;br /&gt;
===For developers===&lt;br /&gt;
&lt;br /&gt;
* MDL-61307 - All plugins must implement [https://docs.moodle.org/dev/Privacy_API Privacy API] to be compliant with GDPR requirements. They must implement the API to report on, export and delete stored user data&lt;br /&gt;
* MDL-56511 - Bootstrap is upgraded to final release of version 4&lt;br /&gt;
* MDL-61869 - Infer rendering of templatables with no render method&lt;br /&gt;
* MDL-61298 - Boost: use navigation node icon&lt;br /&gt;
&lt;br /&gt;
==== Upgrading plugins ====&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;1. Check for changes in core APIs&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Read lib/upgrade.txt to check for the deprecations and core API changes, make sure you applied them to your plugin. Note that entries there are not sorted by priority but rather by integration time. Below is the list of upgrade.txt files that contain information about upgrading from Moodle 3.4 to Moodle 3.5 (note that if you upgrade from earlier versions there may be more files):&lt;br /&gt;
&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/lib/upgrade.txt lib/upgrade.txt] changes to various core APIs, deprecations, functions removal&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/calendar/upgrade.txt calendar/upgrade.txt] changes to Calendar API&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/search/upgrade.txt search/upgrade.txt] changes to Global search API&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/message/upgrade.txt message/upgrade.txt] changes to Messages API&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/course/upgrade.txt course/upgrade.txt] changes to Course API&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;2. Check for changes in the API of your plugin type&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Below is the list of plugin types that had API changes between Moodle 3.4 and 3.5:&lt;br /&gt;
&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/enrol/upgrade.txt enrol/upgrade.txt] Enrolment method plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/mod/upgrade.txt mod/upgrade.txt] Activity module plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/auth/upgrade.txt auth/upgrade.txt] Authentication plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/course/format/upgrade.txt course/format/upgrade.txt] Course format plugins&lt;br /&gt;
* [https://raw.githubusercontent.com/moodle/moodle/master/question/type/upgrade.txt question/type/upgrade.txt] Question type plugins&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;3. Check for changes in the depended plugins&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
If your plugin depends on another plugin or calls methods from another plugin, read upgrade.txt in this plugin directory (if it exists). Below is the list of standard plugins that had changes between Moodle 3.4 and 3.5:&lt;br /&gt;
&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/admin/tool/mobile/upgrade.txt tool_mobile],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/admin/tool/usertours/upgrade.txt tool_usertours],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/assign/upgrade.txt mod_assign],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/feedback/upgrade.txt mod_feedback],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/quiz/upgrade.txt mod_quiz],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/mod/scorm/upgrade.txt mod_scorm],&lt;br /&gt;
[https://raw.githubusercontent.com/moodle/moodle/master/theme/boost/upgrade.txt theme_boost]&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;4. Do a smoke test of your plugin with developer debugging mode&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Make sure to check on both Boost and Clean themes. Bootstrap was upgraded in Moodle 3.5&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;5. Run all behat and phpunit tests&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
 &lt;br /&gt;
==See also==&lt;br /&gt;
*[[Moodle 3.4 release notes]]&lt;br /&gt;
*[[Moodle 3.5.1 release notes]]&lt;br /&gt;
 &lt;br /&gt;
[[Category:Release notes]]&lt;br /&gt;
[[Category:Moodle 3.5]]&lt;br /&gt;
 &lt;br /&gt;
[[fr:Notes de mise à jour de Moodle 3.5]]&lt;br /&gt;
[[es:Notas de Moodle 3.5]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NEWMODULE_Adding_capabilities&amp;diff=54086</id>
		<title>NEWMODULE Adding capabilities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NEWMODULE_Adding_capabilities&amp;diff=54086"/>
		<updated>2018-04-25T13:38:21Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* archetypes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{New_Module}}&lt;br /&gt;
In order to add a capabilities for your &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt; you need to:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==1. Create a file access.php in the &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;/db directory==&lt;br /&gt;
&lt;br /&gt;
This should contain a list of the capabilities that you want to define. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039;  =&amp;gt; RISK_SPAM | RISK_PERSONAL | RISK_XSS | RISK_CONFIG,&lt;br /&gt;
        &#039;captype&#039;      =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039;   =&amp;gt; array(&lt;br /&gt;
            &#039;student&#039;        =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;teacher&#039;        =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;editingteacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;manager&#039;          =&amp;gt; CAP_ALLOW&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    // Add more capabilities here ...&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The various parts of the capability definition are:&lt;br /&gt;
&lt;br /&gt;
===Capability name (&#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;)===&lt;br /&gt;
&lt;br /&gt;
This is the internal name used for this this capability. In addition to this internal name, you should also add the language string &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt; to your module&#039;s language file, to give the capability a name that users will see in the interface.&lt;br /&gt;
&lt;br /&gt;
===riskbitmask===&lt;br /&gt;
&lt;br /&gt;
Allowing people to do various things sometimes requires introducing possible security risks. For example, if you can post to a forum, you can post unsolicited advertising. To a certain extent users have to be trusted. To help administrators and teachers know what the issues are, each capability should list any associated risks. See [[Hardening_new_Roles_system]]. will be reflected in the list of icons of each row of the &#039;Override permissions&#039;-&amp;gt;roles page.&lt;br /&gt;
&lt;br /&gt;
Technically, this value is a bit field, so you should combine the relevant risks constants with the &#039;|&#039; operator. So typical values might be:&lt;br /&gt;
* RISK_SPAM&lt;br /&gt;
* RISK_PERSONAL | RISK_XSS | RISK_DATALOSS&lt;br /&gt;
&lt;br /&gt;
===captype===&lt;br /&gt;
&lt;br /&gt;
Should be either &#039;read&#039; or &#039;write&#039;. &#039;read&#039; is for capabilities that just let you view things. &#039;write&#039; for capabilities that let you change things.&lt;br /&gt;
&lt;br /&gt;
===contextlevel===&lt;br /&gt;
&lt;br /&gt;
The context level where this capability is most relevant. If you are writing a module this will almost always be [[Context|CONTEXT_MODULE]]. (This does not have much effect. It is just used to sort and group capabilities on the define roles and override roles pages.)&lt;br /&gt;
&lt;br /&gt;
===archetypes===&lt;br /&gt;
&lt;br /&gt;
This section defines, for each role type, what default permissions those roles should be given when your module is first installed (or when a new capability is detected on upgrade).&lt;br /&gt;
&lt;br /&gt;
Normally, you just add one line for each role that you want to give the capability to. The line should look like &#039;roletype&#039; =&amp;gt; CAP_ALLOW. Just leave out roles that you do not want to get the capability by default. Very exceptionally, you may need to specify a default permission of CAP_PREVENT, CAP_PROHIBIT.&lt;br /&gt;
&lt;br /&gt;
Note that once a capability is established, permissions will not be automatically overwritten when a module is updated. If permissions have changed, an administrator must manually change or force capabilities to be [[:en:Manage_roles#Reset_role_to_defaults|reset to default]] for a role.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want to specify any roles that will be given your capability by default, you can pass a blank array to the &#039;archetypes&#039; parameter:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;mod/newmodule:dosomething&#039; =&amp;gt; array(&lt;br /&gt;
    &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
    &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
    &#039;archetypes&#039; =&amp;gt; array()&lt;br /&gt;
),&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==2. Get Moodle to load the updated capabilities==&lt;br /&gt;
&lt;br /&gt;
The capabilities you defined are only read (and copied into the Moodle database) when your module is installed or upgraded. So every time you edit the db/access.php file you must&lt;br /&gt;
# Increase your module&#039;s version number by editing the file mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;/version.php.&lt;br /&gt;
# Go to the the Administration ► Notifications page, and click through the steps to let Moodle upgrade itself. You should see the name of your module in one of the steps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==3. Checking the capability in your code==&lt;br /&gt;
&lt;br /&gt;
In order to check whether the current user has a particular capability, you need to use the has_capability function. To do that, first you have to get the appropriate context. In this case, it will be a module context.&lt;br /&gt;
&lt;br /&gt;
1. First we need to get the $cm id, and verify that it is correct (there are lots of different ways you might do this, this is only an example.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$cmid = required_param(&#039;cmid&#039;, PARAM_INT);&lt;br /&gt;
if (!$cm = get_coursemodule_from_id(&#039;&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;&#039;, $cmid)) {&lt;br /&gt;
    error(&amp;quot;Course module ID was incorrect&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Then you get the module context:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$context = get_context_instance(CONTEXT_MODULE, $cm-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Finally, you can actually check the permission&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (has_capability(&#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;&#039;, $context)) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normally, you do 1. and 2. once at the top of a script, and then call has_capability as needed within the script with the appropriate capabilities.&lt;br /&gt;
&lt;br /&gt;
===Useful variations===&lt;br /&gt;
&lt;br /&gt;
====Controlling overall access to a script====&lt;br /&gt;
&lt;br /&gt;
Suppose you have a page that should only be available to users with a particular capability. For example, only users with mod/quiz:viewreports should be able to access mod/quiz/report.php. In cases like this, you can use the require_capability function:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_capability($capability, $context);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
near the top of your script. (As soon as you have got the context and called require_login is a good time.) All this does internally is&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (!has_capability($capability, $context)) {&lt;br /&gt;
    // Display error and exit.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
but using require_capability makes your code simpler and is recommended. (Of course, anywhere you might print a link to a page like this, you should only print the link if the user has the right capability.)&lt;br /&gt;
&lt;br /&gt;
====Getting a list of users with a capability====&lt;br /&gt;
&lt;br /&gt;
Suppose you need to get a list of all the users with a particular capability. (For example, the quiz reports list all the users with the mod/quiz:attempt capability. Then you can use the get_users_by_capability function. &lt;br /&gt;
&lt;br /&gt;
====Checking the permissions of another user====&lt;br /&gt;
&lt;br /&gt;
There is an optional 3rd parameter to has_capability that you can use to check another user&#039;s permissions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
has_capability($capability, $context, $otheruser-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Excluding administrators====&lt;br /&gt;
&lt;br /&gt;
Administrators have a magic &#039;moodle/site:doanything&#039; capability that gives them every other capability. If you wish to disable that magic override for one particular capability check, you can use the optional 4th parameter to has capability:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
has_capability($capability, $context, NULL, false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
However, you normally should not do this.&lt;br /&gt;
&lt;br /&gt;
====Performance considerations====&lt;br /&gt;
&lt;br /&gt;
The has_capability function has been carefully optimised, and is pretty fast and you should not really worry. However, it has to perform a fairly complex computation, and if you are going to make exactly the same has_capability call several times in a page (perhaps in a loop) it is probably worth moving the permission check outside the loop. For example don&#039;t do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
foreach ($attempts as $attempt) {&lt;br /&gt;
    if (has_capability(&#039;mod/quiz:viewreports&#039;, $context)) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Instead do&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$canviewreports = has_capability(&#039;mod/quiz:viewreports&#039;, $context);&lt;br /&gt;
foreach ($attempts as $attempt) {&lt;br /&gt;
    if ($canviewreports) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
get_users_by_capability is a very expensive computation. If you are calling it more than once in your script, you are probably doing something wrong ;-)&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles]]&lt;br /&gt;
* [[Hardening_new_Roles_system]] - information about risks&lt;br /&gt;
* [[NEWMODULE_Documentation]] - NEWMODULE Documentation front page&lt;br /&gt;
&lt;br /&gt;
[[Category:Roles]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NEWMODULE_Adding_capabilities&amp;diff=54085</id>
		<title>NEWMODULE Adding capabilities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NEWMODULE_Adding_capabilities&amp;diff=54085"/>
		<updated>2018-04-25T13:37:47Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* archetypes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{New_Module}}&lt;br /&gt;
In order to add a capabilities for your &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt; you need to:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==1. Create a file access.php in the &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;/db directory==&lt;br /&gt;
&lt;br /&gt;
This should contain a list of the capabilities that you want to define. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039;  =&amp;gt; RISK_SPAM | RISK_PERSONAL | RISK_XSS | RISK_CONFIG,&lt;br /&gt;
        &#039;captype&#039;      =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039;   =&amp;gt; array(&lt;br /&gt;
            &#039;student&#039;        =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;teacher&#039;        =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;editingteacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;manager&#039;          =&amp;gt; CAP_ALLOW&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    // Add more capabilities here ...&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The various parts of the capability definition are:&lt;br /&gt;
&lt;br /&gt;
===Capability name (&#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;)===&lt;br /&gt;
&lt;br /&gt;
This is the internal name used for this this capability. In addition to this internal name, you should also add the language string &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt; to your module&#039;s language file, to give the capability a name that users will see in the interface.&lt;br /&gt;
&lt;br /&gt;
===riskbitmask===&lt;br /&gt;
&lt;br /&gt;
Allowing people to do various things sometimes requires introducing possible security risks. For example, if you can post to a forum, you can post unsolicited advertising. To a certain extent users have to be trusted. To help administrators and teachers know what the issues are, each capability should list any associated risks. See [[Hardening_new_Roles_system]]. will be reflected in the list of icons of each row of the &#039;Override permissions&#039;-&amp;gt;roles page.&lt;br /&gt;
&lt;br /&gt;
Technically, this value is a bit field, so you should combine the relevant risks constants with the &#039;|&#039; operator. So typical values might be:&lt;br /&gt;
* RISK_SPAM&lt;br /&gt;
* RISK_PERSONAL | RISK_XSS | RISK_DATALOSS&lt;br /&gt;
&lt;br /&gt;
===captype===&lt;br /&gt;
&lt;br /&gt;
Should be either &#039;read&#039; or &#039;write&#039;. &#039;read&#039; is for capabilities that just let you view things. &#039;write&#039; for capabilities that let you change things.&lt;br /&gt;
&lt;br /&gt;
===contextlevel===&lt;br /&gt;
&lt;br /&gt;
The context level where this capability is most relevant. If you are writing a module this will almost always be [[Context|CONTEXT_MODULE]]. (This does not have much effect. It is just used to sort and group capabilities on the define roles and override roles pages.)&lt;br /&gt;
&lt;br /&gt;
===archetypes===&lt;br /&gt;
&lt;br /&gt;
This section defines, for each role type, what default permissions those roles should be given when your module is first installed (or when a new capability is detected on upgrade).&lt;br /&gt;
&lt;br /&gt;
Normally, you just add one line for each role that you want to give the capability to. The line should look like &#039;roletype&#039; =&amp;gt; CAP_ALLOW. Just leave out roles that you do not want to get the capability by default. Very exceptionally, you may need to specify a default permission of CAP_PREVENT, CAP_PROHIBIT.&lt;br /&gt;
&lt;br /&gt;
Note that once a capability is established, permissions will not be automatically overwritten when a module is updated. If permissions have changed, an administrator must manually change or force capabilities to be [[:en:Manage_roles#Reset_role_to_defaults|reset to default]] for a role.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want to specify any roles that will be given your capability by default you can pass a blank array to the &#039;archetypes&#039; parameter:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&#039;mod/newmodule:dosomething&#039; =&amp;gt; array(&lt;br /&gt;
    &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
    &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
    &#039;archetypes&#039; =&amp;gt; array()&lt;br /&gt;
),&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==2. Get Moodle to load the updated capabilities==&lt;br /&gt;
&lt;br /&gt;
The capabilities you defined are only read (and copied into the Moodle database) when your module is installed or upgraded. So every time you edit the db/access.php file you must&lt;br /&gt;
# Increase your module&#039;s version number by editing the file mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;/version.php.&lt;br /&gt;
# Go to the the Administration ► Notifications page, and click through the steps to let Moodle upgrade itself. You should see the name of your module in one of the steps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==3. Checking the capability in your code==&lt;br /&gt;
&lt;br /&gt;
In order to check whether the current user has a particular capability, you need to use the has_capability function. To do that, first you have to get the appropriate context. In this case, it will be a module context.&lt;br /&gt;
&lt;br /&gt;
1. First we need to get the $cm id, and verify that it is correct (there are lots of different ways you might do this, this is only an example.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$cmid = required_param(&#039;cmid&#039;, PARAM_INT);&lt;br /&gt;
if (!$cm = get_coursemodule_from_id(&#039;&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;&#039;, $cmid)) {&lt;br /&gt;
    error(&amp;quot;Course module ID was incorrect&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Then you get the module context:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$context = get_context_instance(CONTEXT_MODULE, $cm-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Finally, you can actually check the permission&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (has_capability(&#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;&#039;, $context)) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normally, you do 1. and 2. once at the top of a script, and then call has_capability as needed within the script with the appropriate capabilities.&lt;br /&gt;
&lt;br /&gt;
===Useful variations===&lt;br /&gt;
&lt;br /&gt;
====Controlling overall access to a script====&lt;br /&gt;
&lt;br /&gt;
Suppose you have a page that should only be available to users with a particular capability. For example, only users with mod/quiz:viewreports should be able to access mod/quiz/report.php. In cases like this, you can use the require_capability function:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_capability($capability, $context);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
near the top of your script. (As soon as you have got the context and called require_login is a good time.) All this does internally is&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (!has_capability($capability, $context)) {&lt;br /&gt;
    // Display error and exit.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
but using require_capability makes your code simpler and is recommended. (Of course, anywhere you might print a link to a page like this, you should only print the link if the user has the right capability.)&lt;br /&gt;
&lt;br /&gt;
====Getting a list of users with a capability====&lt;br /&gt;
&lt;br /&gt;
Suppose you need to get a list of all the users with a particular capability. (For example, the quiz reports list all the users with the mod/quiz:attempt capability. Then you can use the get_users_by_capability function. &lt;br /&gt;
&lt;br /&gt;
====Checking the permissions of another user====&lt;br /&gt;
&lt;br /&gt;
There is an optional 3rd parameter to has_capability that you can use to check another user&#039;s permissions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
has_capability($capability, $context, $otheruser-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Excluding administrators====&lt;br /&gt;
&lt;br /&gt;
Administrators have a magic &#039;moodle/site:doanything&#039; capability that gives them every other capability. If you wish to disable that magic override for one particular capability check, you can use the optional 4th parameter to has capability:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
has_capability($capability, $context, NULL, false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
However, you normally should not do this.&lt;br /&gt;
&lt;br /&gt;
====Performance considerations====&lt;br /&gt;
&lt;br /&gt;
The has_capability function has been carefully optimised, and is pretty fast and you should not really worry. However, it has to perform a fairly complex computation, and if you are going to make exactly the same has_capability call several times in a page (perhaps in a loop) it is probably worth moving the permission check outside the loop. For example don&#039;t do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
foreach ($attempts as $attempt) {&lt;br /&gt;
    if (has_capability(&#039;mod/quiz:viewreports&#039;, $context)) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Instead do&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$canviewreports = has_capability(&#039;mod/quiz:viewreports&#039;, $context);&lt;br /&gt;
foreach ($attempts as $attempt) {&lt;br /&gt;
    if ($canviewreports) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
get_users_by_capability is a very expensive computation. If you are calling it more than once in your script, you are probably doing something wrong ;-)&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles]]&lt;br /&gt;
* [[Hardening_new_Roles_system]] - information about risks&lt;br /&gt;
* [[NEWMODULE_Documentation]] - NEWMODULE Documentation front page&lt;br /&gt;
&lt;br /&gt;
[[Category:Roles]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=NEWMODULE_Adding_capabilities&amp;diff=54084</id>
		<title>NEWMODULE Adding capabilities</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=NEWMODULE_Adding_capabilities&amp;diff=54084"/>
		<updated>2018-04-25T13:36:04Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Add archetypes array */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{New_Module}}&lt;br /&gt;
In order to add a capabilities for your &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt; you need to:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==1. Create a file access.php in the &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;/db directory==&lt;br /&gt;
&lt;br /&gt;
This should contain a list of the capabilities that you want to define. For example:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$capabilities = array(&lt;br /&gt;
    &#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;riskbitmask&#039;  =&amp;gt; RISK_SPAM | RISK_PERSONAL | RISK_XSS | RISK_CONFIG,&lt;br /&gt;
        &#039;captype&#039;      =&amp;gt; &#039;write&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039;   =&amp;gt; array(&lt;br /&gt;
            &#039;student&#039;        =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;teacher&#039;        =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;editingteacher&#039; =&amp;gt; CAP_ALLOW,&lt;br /&gt;
            &#039;manager&#039;          =&amp;gt; CAP_ALLOW&lt;br /&gt;
        )&lt;br /&gt;
    ),&lt;br /&gt;
&lt;br /&gt;
    // Add more capabilities here ...&lt;br /&gt;
)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The various parts of the capability definition are:&lt;br /&gt;
&lt;br /&gt;
===Capability name (&#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;)===&lt;br /&gt;
&lt;br /&gt;
This is the internal name used for this this capability. In addition to this internal name, you should also add the language string &amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt; to your module&#039;s language file, to give the capability a name that users will see in the interface.&lt;br /&gt;
&lt;br /&gt;
===riskbitmask===&lt;br /&gt;
&lt;br /&gt;
Allowing people to do various things sometimes requires introducing possible security risks. For example, if you can post to a forum, you can post unsolicited advertising. To a certain extent users have to be trusted. To help administrators and teachers know what the issues are, each capability should list any associated risks. See [[Hardening_new_Roles_system]]. will be reflected in the list of icons of each row of the &#039;Override permissions&#039;-&amp;gt;roles page.&lt;br /&gt;
&lt;br /&gt;
Technically, this value is a bit field, so you should combine the relevant risks constants with the &#039;|&#039; operator. So typical values might be:&lt;br /&gt;
* RISK_SPAM&lt;br /&gt;
* RISK_PERSONAL | RISK_XSS | RISK_DATALOSS&lt;br /&gt;
&lt;br /&gt;
===captype===&lt;br /&gt;
&lt;br /&gt;
Should be either &#039;read&#039; or &#039;write&#039;. &#039;read&#039; is for capabilities that just let you view things. &#039;write&#039; for capabilities that let you change things.&lt;br /&gt;
&lt;br /&gt;
===contextlevel===&lt;br /&gt;
&lt;br /&gt;
The context level where this capability is most relevant. If you are writing a module this will almost always be [[Context|CONTEXT_MODULE]]. (This does not have much effect. It is just used to sort and group capabilities on the define roles and override roles pages.)&lt;br /&gt;
&lt;br /&gt;
===archetypes===&lt;br /&gt;
&lt;br /&gt;
This section defines, for each role type, what default permissions those roles should be given when your module is first installed (or when a new capability is detected on upgrade).&lt;br /&gt;
&lt;br /&gt;
Normally, you just add one line for each role that you want to give the capability to. The line should look like &#039;roletype&#039; =&amp;gt; CAP_ALLOW. Just leave out roles that you do not want to get the capability by default. Very exceptionally, you may need to specify a default permission of CAP_PREVENT, CAP_PROHIBIT.&lt;br /&gt;
&lt;br /&gt;
Note that once a capability is established, permissions will not be automatically overwritten when a module is updated. If permissions have changed, an administrator must manually change or force capabilities to be [[:en:Manage_roles#Reset_role_to_defaults|reset to default]] for a role.&lt;br /&gt;
&lt;br /&gt;
If you don&#039;t want to specify any roles that will be given your capability by default you can pass a blank array to the &#039;archetypes&#039; parameter:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    &#039;mod/newmodule:dosomething&#039; =&amp;gt; array(&lt;br /&gt;
        &#039;captype&#039; =&amp;gt; &#039;read&#039;,&lt;br /&gt;
        &#039;contextlevel&#039; =&amp;gt; CONTEXT_MODULE,&lt;br /&gt;
        &#039;archetypes&#039; =&amp;gt; array()&lt;br /&gt;
    ),&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==2. Get Moodle to load the updated capabilities==&lt;br /&gt;
&lt;br /&gt;
The capabilities you defined are only read (and copied into the Moodle database) when your module is installed or upgraded. So every time you edit the db/access.php file you must&lt;br /&gt;
# Increase your module&#039;s version number by editing the file mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;/version.php.&lt;br /&gt;
# Go to the the Administration ► Notifications page, and click through the steps to let Moodle upgrade itself. You should see the name of your module in one of the steps.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==3. Checking the capability in your code==&lt;br /&gt;
&lt;br /&gt;
In order to check whether the current user has a particular capability, you need to use the has_capability function. To do that, first you have to get the appropriate context. In this case, it will be a module context.&lt;br /&gt;
&lt;br /&gt;
1. First we need to get the $cm id, and verify that it is correct (there are lots of different ways you might do this, this is only an example.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$cmid = required_param(&#039;cmid&#039;, PARAM_INT);&lt;br /&gt;
if (!$cm = get_coursemodule_from_id(&#039;&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;&#039;, $cmid)) {&lt;br /&gt;
    error(&amp;quot;Course module ID was incorrect&amp;quot;);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Then you get the module context:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$context = get_context_instance(CONTEXT_MODULE, $cm-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
3. Finally, you can actually check the permission&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (has_capability(&#039;mod/&amp;lt;&amp;lt;NEWMODULE&amp;gt;&amp;gt;:&amp;lt;&amp;lt;CAPABILITYNAME&amp;gt;&amp;gt;&#039;, $context)) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Normally, you do 1. and 2. once at the top of a script, and then call has_capability as needed within the script with the appropriate capabilities.&lt;br /&gt;
&lt;br /&gt;
===Useful variations===&lt;br /&gt;
&lt;br /&gt;
====Controlling overall access to a script====&lt;br /&gt;
&lt;br /&gt;
Suppose you have a page that should only be available to users with a particular capability. For example, only users with mod/quiz:viewreports should be able to access mod/quiz/report.php. In cases like this, you can use the require_capability function:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_capability($capability, $context);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
near the top of your script. (As soon as you have got the context and called require_login is a good time.) All this does internally is&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (!has_capability($capability, $context)) {&lt;br /&gt;
    // Display error and exit.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
but using require_capability makes your code simpler and is recommended. (Of course, anywhere you might print a link to a page like this, you should only print the link if the user has the right capability.)&lt;br /&gt;
&lt;br /&gt;
====Getting a list of users with a capability====&lt;br /&gt;
&lt;br /&gt;
Suppose you need to get a list of all the users with a particular capability. (For example, the quiz reports list all the users with the mod/quiz:attempt capability. Then you can use the get_users_by_capability function. &lt;br /&gt;
&lt;br /&gt;
====Checking the permissions of another user====&lt;br /&gt;
&lt;br /&gt;
There is an optional 3rd parameter to has_capability that you can use to check another user&#039;s permissions:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
has_capability($capability, $context, $otheruser-&amp;gt;id);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Excluding administrators====&lt;br /&gt;
&lt;br /&gt;
Administrators have a magic &#039;moodle/site:doanything&#039; capability that gives them every other capability. If you wish to disable that magic override for one particular capability check, you can use the optional 4th parameter to has capability:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
has_capability($capability, $context, NULL, false);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
However, you normally should not do this.&lt;br /&gt;
&lt;br /&gt;
====Performance considerations====&lt;br /&gt;
&lt;br /&gt;
The has_capability function has been carefully optimised, and is pretty fast and you should not really worry. However, it has to perform a fairly complex computation, and if you are going to make exactly the same has_capability call several times in a page (perhaps in a loop) it is probably worth moving the permission check outside the loop. For example don&#039;t do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
foreach ($attempts as $attempt) {&lt;br /&gt;
    if (has_capability(&#039;mod/quiz:viewreports&#039;, $context)) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Instead do&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$canviewreports = has_capability(&#039;mod/quiz:viewreports&#039;, $context);&lt;br /&gt;
foreach ($attempts as $attempt) {&lt;br /&gt;
    if ($canviewreports) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
get_users_by_capability is a very expensive computation. If you are calling it more than once in your script, you are probably doing something wrong ;-)&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Access API]]&lt;br /&gt;
* [[Roles]]&lt;br /&gt;
* [[Hardening_new_Roles_system]] - information about risks&lt;br /&gt;
* [[NEWMODULE_Documentation]] - NEWMODULE Documentation front page&lt;br /&gt;
&lt;br /&gt;
[[Category:Roles]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=53723</id>
		<title>SCORM reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=SCORM_reports&amp;diff=53723"/>
		<updated>2018-02-28T07:05:51Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Add Category */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.2}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
SCORM reports were converted to a pluggable architecture as of MOODLE 2.2. The original documentation of the project can be found at [https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements]. Scorm Reports define a way for developer to develop reports of their own for the scorm module. The rest of this page deals with the details of how to develop such a report.&lt;br /&gt;
== Template ==&lt;br /&gt;
Here is a basic template for scorm report plugin on [https://github.com/ankitagarwal/scorm_report_template Github]&lt;br /&gt;
== File structure ==&lt;br /&gt;
Each plugin is allowed to have following files and folders:&lt;br /&gt;
&lt;br /&gt;
=== Mandatory Files ===&lt;br /&gt;
* classes/report.php&lt;br /&gt;
* lang/xx/scormreport_pluginname.php&lt;br /&gt;
&lt;br /&gt;
=== Other Optional Files ===&lt;br /&gt;
* Version.php&lt;br /&gt;
* db/install.php&lt;br /&gt;
* db/install.xml&lt;br /&gt;
* db/upgrade.php&lt;br /&gt;
* db/access.php&lt;br /&gt;
Please refer [[Upgrade API]] and [[Access API]] to understand the working of above files.&lt;br /&gt;
&lt;br /&gt;
As you might have noticed the file structure for scorm report plugin is similar to any other standard plugin in Moodle. The only differences are:-&lt;br /&gt;
* There must be a file classes/report.php implementing class \scormreport_yourreport\report that must extend the default reporting class &amp;quot;\mod_scorm\report&amp;quot; and the extended class must implement the method &amp;quot;display($scorm, $cm, $course, $download)&amp;quot;, which should handle the core reporting feature.&lt;br /&gt;
* The lang file is not optional. That is, each plugin must define the string &amp;quot;pluginname&amp;quot; in the lang files.&lt;br /&gt;
&lt;br /&gt;
== Naming Conventions ==&lt;br /&gt;
Following Naming conventions should be kept in mind while writing a scorm report plugin:-&lt;br /&gt;
* Folder name should be same as pluginname&lt;br /&gt;
* Name of the extended class should be in format \scormreport_myreport\report&lt;br /&gt;
* \scormreport_myreport\report must implement the function&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
   function display($scorm, $cm, $course, $download) {}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* Each plugin must define the string &amp;quot;pluginname&amp;quot; in the language files.&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
[https://docs.moodle.org/dev/SCORM_reporting_improvements SCORM Reporting Improvements] Original GSOC 2011 Project Documentation&lt;br /&gt;
=== User Docs ===&lt;br /&gt;
[https://docs.moodle.org/en/Using_SCORM Using SCORM]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_FAQ SCORM FAQ]&lt;br /&gt;
&lt;br /&gt;
[https://docs.moodle.org/en/SCORM_module SCORM Module]&lt;br /&gt;
&lt;br /&gt;
[[Category:SCORM]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=53498</id>
		<title>lib/formslib.php Form Definition</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Form_Definition&amp;diff=53498"/>
		<updated>2017-12-12T07:11:27Z</updated>

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

		<summary type="html">&lt;p&gt;Libertymoodle: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to get files from users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 all files are stored in a central database accessible via the [[File API|File API]], and every file is associated with a component and a &amp;quot;file area&amp;quot; in Moodle, such as a particular module.&lt;br /&gt;
&lt;br /&gt;
A common use case is to provide a form (using Moodle&#039;s [[lib/formslib.php|Forms API]]) which allows users to upload or import files as attachments or media embedded into HTML.&lt;br /&gt;
&lt;br /&gt;
Normally this works like this:&lt;br /&gt;
# User starts creation or re-edits an existing item in Moodle (eg forum post, resource, glossary entry etc)&lt;br /&gt;
# User presses some sort of button to browse for new files to attach or embed&lt;br /&gt;
# User sees our &amp;quot;Choose file...&amp;quot; dialog, which contains one or more repository instances. &lt;br /&gt;
# User chooses a file, the corresponding [[Repository plugins|Repository plugin]] takes care of copying the file into a &amp;quot;draft file area&amp;quot; within Moodle&lt;br /&gt;
# File appears in the text or as an attachment in the form.&lt;br /&gt;
# When the user hits save, the [[File API|File API]] is invoked to move the file from the draft file area into a permanent file area associated with that data &lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to interact with users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
If you just want to write code to manipulate Moodle files internally (without user input) then see [[File API]].&lt;br /&gt;
&lt;br /&gt;
==Form elements== &lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 there are three file-related form elements for interacting with users:&lt;br /&gt;
&lt;br /&gt;
# filemanager - the way to attach one or more files as a set&lt;br /&gt;
# editor - the way to specify a textarea with a HTML editor, and all the handling of images and movies within that HTML&lt;br /&gt;
# filepicker - a way to specify one file for the case when you want to process the file and throw it away &lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9 there were two other types which are now &#039;&#039;&#039;deprecated&#039;&#039;&#039; (they work, but please do not use these anymore)&lt;br /&gt;
# file - used to just allow a normal file upload from the desktop only.&lt;br /&gt;
# htmleditor - this old method of embedding a HTML editor in a textarea is not able to support repositories etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===filepicker===&lt;br /&gt;
&lt;br /&gt;
File picker (&#039;&#039;filepicker&#039;&#039;) is a direct replacement of the older &#039;&#039;file&#039;&#039; formslib element. &lt;br /&gt;
&lt;br /&gt;
It is intended for situations when you want the user to upload &#039;&#039;&#039;one&#039;&#039;&#039; file so you can process it and delete it, such as when you are importing data from a CSV file.&lt;br /&gt;
If you want a file that remains part of the Moodle storage and will reappear when you reopen the form, then you should use a filemanager instead (and restrict it to a single file, if necessary).&lt;br /&gt;
&lt;br /&gt;
==== Using the filepicker element ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null,&lt;br /&gt;
                   array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtain the chosen file ====&lt;br /&gt;
&lt;br /&gt;
To get the contents of the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content = $mform-&amp;gt;get_file_content(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To get the name of the chosen file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$name = $mform-&amp;gt;get_new_filename(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To save the chosen file to the server filesystem (such as to moodledata folder):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$success = $mform-&amp;gt;save_file(&#039;userfile&#039;, $fullpath, $override);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To store the chosen file in the Moodle files pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$storedfile = $mform-&amp;gt;save_stored_file(&#039;userfile&#039;, ...);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== filemanager ===&lt;br /&gt;
&lt;br /&gt;
The File Manager element improves on file picker by allowing you to manage more than one file.  It is expected that the files will be stored permanently for future use (such as forum and glossary attachments).&lt;br /&gt;
&lt;br /&gt;
==== Add file manager element ====&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachments&#039;, get_string(&#039;attachment&#039;, &#039;moodle&#039;), null,&lt;br /&gt;
                    array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;areamaxbytes&#039; =&amp;gt; 10485760, &#039;maxfiles&#039; =&amp;gt; 50,&lt;br /&gt;
                          &#039;accepted_types&#039; =&amp;gt; array(&#039;document&#039;), &#039;return_types&#039;=&amp;gt; FILE_INTERNAL | FILE_EXTERNAL));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are the fields for filemanager:&lt;br /&gt;
&lt;br /&gt;
;&#039;filemanager&#039;:This is a filemanager element :)&lt;br /&gt;
;elementname:The unique name of the element in the form&lt;br /&gt;
;elementlabel:The label string that users see &lt;br /&gt;
;attributes:(leave it as null)&lt;br /&gt;
;options: an array of further options for the filepicker (see below)&lt;br /&gt;
&lt;br /&gt;
The options array can contain:&lt;br /&gt;
&lt;br /&gt;
;subdirs:(Default 1) Are subdirectories allowed?  (true or false)&lt;br /&gt;
;maxbytes:(Default 0) Restricts the size of each individual file.&lt;br /&gt;
;areamaxbytes:(Default 0) Restricts the total size of all the files.&lt;br /&gt;
;maxfiles:(Default -1) Restricts the total number of files.&lt;br /&gt;
;accepted_types:(Default *) You can specify what file types are accepted by filemanager.  All current file types are listed in this file: [http://cvs.moodle.org/moodle/lib/filestorage/file_types.mm moodle/lib/filestorage/file_types.mm].  This is a [http://freemind.sourceforge.net/wiki/index.php/Main_Page freemind] file: if it is edited the changes will be immediately reflected in Moodle.&lt;br /&gt;
&lt;br /&gt;
As of 2.3 file_types.mm is no longer used, instead the file types are listed in &amp;lt;code&amp;gt;get_mimetypes_array()&amp;lt;/code&amp;gt; in filelib.php (https://github.com/moodle/moodle/blob/master/lib/classes/filetypes.php).&lt;br /&gt;
&lt;br /&gt;
Example usage:  &#039;&#039;&#039;array(&#039;audio&#039;, &#039;video&#039;, &#039;document&#039;)&#039;&#039;&#039;, you can include file extensions as well, for example: &#039;&#039;&#039;array(&#039;.txt&#039;, &#039;.jpg&#039;, &#039;audio&#039;)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Load existing files into draft area ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
    $entry = new stdClass;&lt;br /&gt;
    $entry-&amp;gt;id = null;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftitemid = file_get_submitted_draft_itemid(&#039;attachments&#039;);&lt;br /&gt;
&lt;br /&gt;
file_prepare_draft_area($draftitemid, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id,&lt;br /&gt;
                        array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
&lt;br /&gt;
$entry-&amp;gt;attachments = $draftitemid;&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Store updated set of files ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // ... store or update $entry&lt;br /&gt;
    file_save_draft_area_files($data-&amp;gt;attachments, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;,&lt;br /&gt;
                   $entry-&amp;gt;id, array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===editor===&lt;br /&gt;
There are two ways of using the editor element in code, the first one is easier but expects some standardized fields. The second method is more low level.&lt;br /&gt;
&lt;br /&gt;
====Simple use====&lt;br /&gt;
# name database fields: &#039;&#039;textfield&#039;&#039;, &#039;&#039;textfieldformat&#039;&#039; (and &#039;&#039;textfieldtrust&#039;&#039; if required)&lt;br /&gt;
# create options array.  note that context is the best, most local context you have available.&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$textfieldoptions = array(&#039;trusttext&#039;=&amp;gt;true, &#039;subdirs&#039;=&amp;gt;true, &#039;maxfiles&#039;=&amp;gt;$maxfiles, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;context&#039;=&amp;gt;$context);&amp;lt;/code&amp;gt;&lt;br /&gt;
# add editor &#039;&#039;textfield_editor&#039;&#039; to moodle form, pass options through custom data in form constructor, set $data-&amp;gt;id to null if data not exist yet&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;textfield_editor&#039;, get_string(&#039;fieldname&#039;, &#039;somemodule&#039;), null, $textfieldoptions);&amp;lt;/code&amp;gt;&lt;br /&gt;
# prepare data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_prepare_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
# get submitted data and after inserting/updating of data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_postupdate_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Real world examples are in mod/glossary/edit.php and mod/glossary/comment.php&lt;br /&gt;
&lt;br /&gt;
====Low level use====&lt;br /&gt;
&lt;br /&gt;
When using editor element you  need to preprocess and postprocess the data:&lt;br /&gt;
# detect if form was already submitted (usually means draft is area already exists) - &#039;&#039;file_get_submitted_draft_itemid()&#039;&#039;&lt;br /&gt;
# prepare draft file area, temporary storage of all files attached to the text - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# convert encoded relative links to absolute links - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# create form and set current data&lt;br /&gt;
# after submission the changed files must be merged back into original area - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
# absolute links have to be replaced by relative links - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=====Replace old htmleditor with editor=====&lt;br /&gt;
&lt;br /&gt;
The file picker has been integrated with with TinyMCE to make the editor element. This new element should support all types on editors and should be able to switch them on-the-fly. Instances of the old htmleditor element in your forms should be replaced by the new editor element, this may need adding of new format and trusttext columns. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;entry&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; EDITOR_UNLIMITED_FILES));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The editor element can take following options: maxfiles, maxbytes, subdirs and changeformat. Please note that the embedded files is optional feature and is not expected be used everywhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the editor element now includes text format option. You should no longer use the separate format element type.&lt;br /&gt;
&lt;br /&gt;
=====Prepare current data - text and files=====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
  $entry = new object();&lt;br /&gt;
  $entry-&amp;gt;id = null;&lt;br /&gt;
  $entry-&amp;gt;definition = &#039;&#039;;&lt;br /&gt;
  $entry-&amp;gt;format = FORMAT_HTML;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftid_editor = file_get_submitted_draft_itemid(&#039;entry&#039;);&lt;br /&gt;
$currenttext = file_prepare_draft_area($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                       $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $entry-&amp;gt;definition);&lt;br /&gt;
$entry-&amp;gt;entry = array(&#039;text&#039;=&amp;gt;$currenttext, &#039;format&#039;=&amp;gt;$entry-&amp;gt;format, &#039;itemid&#039;=&amp;gt;$draftid_editor);&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are multiple files, they will share the same itemid.&lt;br /&gt;
&lt;br /&gt;
=====Obtain text, format and save draft files=====&lt;br /&gt;
&lt;br /&gt;
To retrieve editor content, you need to use following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // content of editor&lt;br /&gt;
    $messagetext = $fromform-&amp;gt;entry[&#039;text&#039;];&lt;br /&gt;
    // format of content&lt;br /&gt;
    $messageformat  = $fromform-&amp;gt;entry[&#039;format&#039;];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a user selects a file using the file picker, the file is initially stored in a draft file area, and a URL is inserted into the HTML in the editor that lets the person editing the content (but no one else) see the file.&lt;br /&gt;
&lt;br /&gt;
When the user submits the form, we then need to save the draft files to the correct place in permanent storage. (Just like you have to call $DB-&amp;gt;update_record(&#039;tablename&#039;, $data); to have the other parts of the form submission stored correctly.)&lt;br /&gt;
&lt;br /&gt;
The save_files_from_draft_area function and replace absolute links with internal relative links do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_save_draft_area_files($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                          $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $messagetext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $context-&amp;gt;id, &#039;component&#039;, &#039;proper_file_area&#039; and $entry-&amp;gt;id : correspond to the contextid, filearea and itemid columns in the [[File_API#Table:_files|files table]].&lt;br /&gt;
; $messagetext : this is the message text. As the files are saved to the real file area, the URLs in this content are rewritten.&lt;br /&gt;
&lt;br /&gt;
All URLs in content that point to files managed to the File API are converted to a form that starts &#039;@@PLUGINFILE@@/&#039; before the content is stored in the database. That is what we mean by rewriting.&lt;br /&gt;
&lt;br /&gt;
== File serving==&lt;br /&gt;
&lt;br /&gt;
=== Convert internal relative links to absolute links ===&lt;br /&gt;
&lt;br /&gt;
Before text content is displayed to the user, any URLs in the &#039;@@PLUGINFILE@@/&#039; form in the content need to be rewritten to the real URL where the user can access the files. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_rewrite_pluginfile_urls($messagetext, &#039;pluginfile.php&#039;,&lt;br /&gt;
        $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $messagetext : is the content containing the @@PLUGINFILE@@ URLs from the database.&lt;br /&gt;
; &#039;pluginfile.php&#039; : there are a number of different scripts that can serve files with different permissions checks. You need to specify which one to use.&lt;br /&gt;
; $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid : uniquely identifies the file area, as before.&lt;br /&gt;
&lt;br /&gt;
=== Implement file serving access control ===&lt;br /&gt;
&lt;br /&gt;
Attachments and embedded images should have the same access control like the text itself, in majority of cases these files are served using pluginfile.php. Access control is defined in &#039;&#039;module/lib.php&#039;&#039; file in function &#039;&#039;module_pluginfile()&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== File browsing support ==&lt;br /&gt;
Only owner of each file area is allowed to use low level File API function to access files, other parts of Moodle should use file browsing API.&lt;br /&gt;
&lt;br /&gt;
Activities may specify browsing support in own module/lib.php file by implementing functions module_get_file_areas() and module_get_file_info().&lt;br /&gt;
&lt;br /&gt;
== Upgrading your code ==&lt;br /&gt;
Here I will attempt to describe some simple steps you can take to upgrade your file-handling form elements from pre-2.0 code to 2.0. We will use the example of glossary, since it has been used above.&lt;br /&gt;
&lt;br /&gt;
=== Preparing your options ===&lt;br /&gt;
Unless you are happy with the defaults, you will need to define an array of options for each file-handling form element. You could define it at different places, but it&#039;s best to put it in one place and make the array(s) available to other files if they need it. In the majority of cases, this will be in a file like edit.php&lt;br /&gt;
&lt;br /&gt;
Previous code in mod/glossary/edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform =&amp;amp; new mod_glossary_entry_form(null, compact(&#039;cm&#039;, &#039;glossary&#039;, &#039;hook&#039;, &#039;mode&#039;, &#039;e&#039;, &#039;context&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$maxbytes = $course-&amp;gt;maxbytes;&lt;br /&gt;
// Could also use $CFG-&amp;gt;maxbytes if you are not coding within a course context&lt;br /&gt;
&lt;br /&gt;
$definitionoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;trusttext&#039;=&amp;gt;true,&lt;br /&gt;
                           &#039;context&#039;=&amp;gt;$context);&lt;br /&gt;
$attachmentoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that the data being passed to the form constructor have changed also, but this is not part of the file API changes, I just include them to avoid confusion.&lt;br /&gt;
&lt;br /&gt;
These options are for the htmleditor (definition field) and the filemanager (attachment field). They are used by a file called edit_form.php.&lt;br /&gt;
&lt;br /&gt;
=== Element preparation ===&lt;br /&gt;
Before we look at this, however, we need to &amp;quot;prepare&amp;quot; the elements so that they can correctly display existing embedded images and attached files when you are editing a record instead of just creating one. So, let&#039;s take the code we&#039;ve got so far in edit.php and add to it:&lt;br /&gt;
&lt;br /&gt;
Currently upgraded code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code with element preparation:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$entry = file_prepare_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                      &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_prepare_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                           &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* $entry in this case is simply a stdClass object which may either represent a new glossary entry or an existing one.&lt;br /&gt;
* $entry-&amp;gt;id must be the unique identifier for the current object. If we are creating a new entry, it will be null, but in all cases it must be defined.&lt;br /&gt;
* These two functions (file_prepare_standard_editor and file_prepare_standard_filemanager) are shortcuts functions that take care of some of the tedious setting up for you, but they make a couple of assumptions:&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; name the form element as {element}_editor or {element}_filemanager (see next section)&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; have at least the following fields in the database: {element} and {element}summary, as described earlier in this documentation&lt;br /&gt;
&lt;br /&gt;
We can now look at the upgrades needed in the form definition file.&lt;br /&gt;
&lt;br /&gt;
=== Form definition ===&lt;br /&gt;
Previous code in mod/glossary/edit_form.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;htmleditor&#039;, &#039;definition&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;),&lt;br /&gt;
                    array(&#039;rows&#039;=&amp;gt;20));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition&#039;, null, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;definition&#039;, array(&#039;writing&#039;, &#039;richtext&#039;), false, &#039;editorhelpbutton&#039;);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;format&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0,&lt;br /&gt;
                                             true, true, false));&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment&#039;, array(&#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                      &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$definitionoptions = $this-&amp;gt;_customdata[&#039;definitionoptions&#039;];&lt;br /&gt;
$attachmentoptions = $this-&amp;gt;_customdata[&#039;attachmentoptions&#039;];&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;definition_editor&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
                   $definitionoptions);&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition_editor&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition_editor&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachment_filemanager&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                   null, $attachmentoptions);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment_filemanager&#039;, array(&#039;attachment2&#039;,&lt;br /&gt;
                      get_string(&#039;attachment&#039;, &#039;glossary&#039;), &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the following:&lt;br /&gt;
* The format element and the help button are no longer required for the HTML editor element&lt;br /&gt;
* The name of the form element needs to be changed by adding &#039;_editor&#039; or &#039;_manager&#039; to the original name. This is a naming convention that is used by a couple of functions we will look at shortly&lt;br /&gt;
* Make sure $definitionoptions has context parameter, else system context is used and editor will not respect filter settings.&lt;br /&gt;
&lt;br /&gt;
=== Handling submitted data ===&lt;br /&gt;
The final step is to handle the submitted data properly, i.e. retrieve the files and save them to disk, associating them with the record we have just created (a glossary entry in our example). This happens in edit.php:&lt;br /&gt;
&lt;br /&gt;
Previous code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Section that updates an entry:&lt;br /&gt;
$todb-&amp;gt;id = $e;&lt;br /&gt;
$dir = glossary_file_area_name($todb);&lt;br /&gt;
if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
    $todb-&amp;gt;attachment = $newfilename;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Section that adds an entry:&lt;br /&gt;
if ($todb-&amp;gt;id = insert_record(&amp;quot;glossary_entries&amp;quot;, $todb)) {&lt;br /&gt;
    $e = $todb-&amp;gt;id;&lt;br /&gt;
    $dir = glossary_file_area_name($todb);&lt;br /&gt;
    if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
        set_field(&amp;quot;glossary_entries&amp;quot;, &amp;quot;attachment&amp;quot;, $newfilename, &amp;quot;id&amp;quot;, $todb-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// $todb was renamed to $entry, and the code was refactored &lt;br /&gt;
// so that the file-handling code is only used once for either an add or an update action.&lt;br /&gt;
// If an entry is being added, $DB-&amp;gt;insert() has already been called, so we have a valid $entry-&amp;gt;id&lt;br /&gt;
$entry = file_postupdate_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                         &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_postupdate_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                              &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
// store the updated value values&lt;br /&gt;
$DB-&amp;gt;update_record(&#039;glossary_entries&#039;, $entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* If you are adding a new record, you will still need to call update_record after calling the file_postupdate* functions&lt;br /&gt;
&lt;br /&gt;
=== Gotchas ===&lt;br /&gt;
A few things to keep in mind:&lt;br /&gt;
* Make sure that you instantiate the moodle form before any call to $OUTPUT-&amp;gt;header()&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Using the file API]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
* MDL-14589 - File API Meta issue&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=207748 Adding a text editor to a Moodle form]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=157953#p692822 Button actions in Moodle form]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=351013#p1416554 File Picker]&lt;br /&gt;
&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51873</id>
		<title>Using the File API in Moodle forms</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51873"/>
		<updated>2017-02-10T13:10:55Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* See also - typo */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to get files from users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 all files are stored in a central database accessible via the [[File API|File API]], and every file is associated with a component and a &amp;quot;file area&amp;quot; in Moodle, such as a particular module.&lt;br /&gt;
&lt;br /&gt;
A common use case is to provide a form (using Moodle&#039;s [[lib/formslib.php|Forms API]]) which allows users to upload or import files as attachments or media embedded into HTML.&lt;br /&gt;
&lt;br /&gt;
Normally this works like this:&lt;br /&gt;
# User starts creation or re-edits an existing item in Moodle (eg forum post, resource, glossary entry etc)&lt;br /&gt;
# User presses some sort of button to browse for new files to attach or embed&lt;br /&gt;
# User sees our &amp;quot;Choose file...&amp;quot; dialog, which contains one or more repository instances. &lt;br /&gt;
# User chooses a file, the corresponding [[Repository plugins|Repository plugin]] takes care of copying the file into a &amp;quot;draft file area&amp;quot; within Moodle&lt;br /&gt;
# File appears in the text or as an attachment in the form.&lt;br /&gt;
# When the user hits save, the [[File API|File API]] is invoked to move the file from the draft file area into a permanent file area associated with that data &lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to interact with users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
If you just want to write code to manipulate Moodle files internally (without user input) then see [[File API]].&lt;br /&gt;
&lt;br /&gt;
==Form elements== &lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 there are three file-related form elements for interacting with users:&lt;br /&gt;
&lt;br /&gt;
# filemanager - the way to attach one or more files as a set&lt;br /&gt;
# editor - the way to specify a textarea with a HTML editor, and all the handling of images and movies within that HTML&lt;br /&gt;
# filepicker - a way to specify one file for the case when you want to process the file and throw it away &lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9 there were two other types which are now &#039;&#039;&#039;deprecated&#039;&#039;&#039; (they work, but please do not use these anymore)&lt;br /&gt;
# file - used to just allow a normal file upload from the desktop only.&lt;br /&gt;
# htmleditor - this old method of embedding a HTML editor in a textarea is not able to support repositories etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===filepicker===&lt;br /&gt;
&lt;br /&gt;
File picker (&#039;&#039;filepicker&#039;&#039;) is a direct replacement of the older &#039;&#039;file&#039;&#039; formslib element. &lt;br /&gt;
&lt;br /&gt;
It is intended for situations when you want the user to upload &#039;&#039;&#039;one&#039;&#039;&#039; file so you can process it and delete it, such as when you are importing data from a CSV file.&lt;br /&gt;
If you want a file that remains part of the Moodle storage and will reappear when you reopen the form, then you should use a filemanager instead (and restrict it to a single file, if necessary).&lt;br /&gt;
&lt;br /&gt;
==== Using the filepicker element ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null,&lt;br /&gt;
                   array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtain the chosen file ====&lt;br /&gt;
&lt;br /&gt;
To get the contents of the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content = $mform-&amp;gt;get_file_content(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To get the name of the chosen file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$name = $mform-&amp;gt;get_new_filename(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To save the chosen file to the server filesystem (such as to moodledata folder):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$success = $mform-&amp;gt;save_file(&#039;userfile&#039;, $fullpath, $override);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To store the chosen file in the Moodle files pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$storedfile = $mform-&amp;gt;save_stored_file(&#039;userfile&#039;, ...);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== filemanager ===&lt;br /&gt;
&lt;br /&gt;
The File Manager element improves on file picker by allowing you to manage more than one file.  It is expected that the files will be stored permanently for future use (such as forum and glossary attachments).&lt;br /&gt;
&lt;br /&gt;
==== Add file manager element ====&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachments&#039;, get_string(&#039;attachment&#039;, &#039;moodle&#039;), null,&lt;br /&gt;
                    array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;areamaxbytes&#039; =&amp;gt; 10485760, &#039;maxfiles&#039; =&amp;gt; 50,&lt;br /&gt;
                          &#039;accepted_types&#039; =&amp;gt; array(&#039;document&#039;), &#039;return_types&#039;=&amp;gt; FILE_INTERNAL | FILE_EXTERNAL));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are the fields for filemanager:&lt;br /&gt;
&lt;br /&gt;
;&#039;filemanager&#039;:This is a filemanager element :)&lt;br /&gt;
;elementname:The unique name of the element in the form&lt;br /&gt;
;elementlabel:The label string that users see &lt;br /&gt;
;attributes:(leave it as null)&lt;br /&gt;
;options: an array of further options for the filepicker (see below)&lt;br /&gt;
&lt;br /&gt;
The options array can contain:&lt;br /&gt;
&lt;br /&gt;
;subdirs:(Default 1) Are subdirectories allowed?  (true or false)&lt;br /&gt;
;maxbytes:(Default 0) Restricts the size of each individual file.&lt;br /&gt;
;areamaxbytes:(Default 0) Restricts the total size of all the files.&lt;br /&gt;
;maxfiles:(Default -1) Restricts the total number of files.&lt;br /&gt;
;accepted_types:(Default *) You can specify what file types are accepted by filemanager.  All current file types are listed in this file: [http://cvs.moodle.org/moodle/lib/filestorage/file_types.mm moodle/lib/filestorage/file_types.mm].  This is a [http://freemind.sourceforge.net/wiki/index.php/Main_Page freemind] file: if it is edited the changes will be immediately reflected in Moodle.&lt;br /&gt;
&lt;br /&gt;
As of 2.3 file_types.mm is no longer used, instead the file types are listed in &amp;lt;code&amp;gt;get_mimetypes_array()&amp;lt;/code&amp;gt; in filelib.php (https://github.com/moodle/moodle/blob/master/lib/classes/filetypes.php).&lt;br /&gt;
&lt;br /&gt;
Example usage:  &#039;&#039;&#039;array(&#039;audio&#039;, &#039;video&#039;, &#039;document&#039;)&#039;&#039;&#039;, you can include file extensions as well, for example: &#039;&#039;&#039;array(&#039;.txt&#039;, &#039;.jpg&#039;, &#039;audio&#039;)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Load existing files into draft area ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
    $entry = new stdClass;&lt;br /&gt;
    $entry-&amp;gt;id = null;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftitemid = file_get_submitted_draft_itemid(&#039;attachments&#039;);&lt;br /&gt;
&lt;br /&gt;
file_prepare_draft_area($draftitemid, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id,&lt;br /&gt;
                        array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
&lt;br /&gt;
$entry-&amp;gt;attachments = $draftitemid;&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Store updated set of files ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // ... store or update $entry&lt;br /&gt;
    file_save_draft_area_files($data-&amp;gt;attachments, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;,&lt;br /&gt;
                   $entry-&amp;gt;id, array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===editor===&lt;br /&gt;
There are two ways of using the editor element in code, the first one is easier but expects some standardized fields. The second method is more low level.&lt;br /&gt;
&lt;br /&gt;
====Simple use====&lt;br /&gt;
# name database fields: &#039;&#039;textfield&#039;&#039;, &#039;&#039;textfieldformat&#039;&#039; (and &#039;&#039;textfieldtrust&#039;&#039; if required)&lt;br /&gt;
# create options array.  note that context is the best, most local context you have available.&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$textfieldoptions = array(&#039;trusttext&#039;=&amp;gt;true, &#039;subdirs&#039;=&amp;gt;true, &#039;maxfiles&#039;=&amp;gt;$maxfiles, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;context&#039;=&amp;gt;$context);&amp;lt;/code&amp;gt;&lt;br /&gt;
# add editor &#039;&#039;textfield_editor&#039;&#039; to moodle form, pass options through custom data in form constructor, set $data-&amp;gt;id to null if data not exist yet&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;textfield_editor&#039;, get_string(&#039;fieldname&#039;, &#039;somemodule&#039;), null, $textfieldoptions);&amp;lt;/code&amp;gt;&lt;br /&gt;
# prepare data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_prepare_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
# get submitted data and after inserting/updating of data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_postupdate_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Real world examples are in mod/glossary/edit.php and mod/glossary/comment.php&lt;br /&gt;
&lt;br /&gt;
====Low level use====&lt;br /&gt;
&lt;br /&gt;
When using editor element you  need to preprocess and postprocess the data:&lt;br /&gt;
# detect if form was already submitted (usually means draft is area already exists) - &#039;&#039;file_get_submitted_draft_itemid()&#039;&#039;&lt;br /&gt;
# prepare draft file area, temporary storage of all files attached to the text - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# convert encoded relative links to absolute links - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# create form and set current data&lt;br /&gt;
# after submission the changed files must be merged back into original area - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
# absolute links have to be replaced by relative links - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=====Replace old htmleditor with editor=====&lt;br /&gt;
&lt;br /&gt;
The file picker has been integrated with with TinyMCE to make the editor element. This new element should support all types on editors and should be able to switch them on-the-fly. Instances of the old htmleditor element in your forms should be replaced by the new editor element, this may need adding of new format and trusttext columns. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;entry&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; EDITOR_UNLIMITED_FILES));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The editor element can take following options: maxfiles, maxbytes, subdirs and changeformat. Please note that the embedded files is optional feature and is not expected be used everywhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the editor element now includes text format option. You should no longer use the separate format element type.&lt;br /&gt;
&lt;br /&gt;
=====Prepare current data - text and files=====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
  $entry = new object();&lt;br /&gt;
  $entry-&amp;gt;id = null;&lt;br /&gt;
  $entry-&amp;gt;definition = &#039;&#039;;&lt;br /&gt;
  $entry-&amp;gt;format = FORMAT_HTML;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftid_editor = file_get_submitted_draft_itemid(&#039;entry&#039;);&lt;br /&gt;
$currenttext = file_prepare_draft_area($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                       $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $entry-&amp;gt;definition);&lt;br /&gt;
$entry-&amp;gt;entry = array(&#039;text&#039;=&amp;gt;$currenttext, &#039;format&#039;=&amp;gt;$entry-&amp;gt;format, &#039;itemid&#039;=&amp;gt;$draftid_editor);&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are multiple files, they will share the same itemid.&lt;br /&gt;
&lt;br /&gt;
=====Obtain text, format and save draft files=====&lt;br /&gt;
&lt;br /&gt;
To retrieve editor content, you need to use following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // content of editor&lt;br /&gt;
    $messagetext = $fromform-&amp;gt;entry[&#039;text&#039;];&lt;br /&gt;
    // format of content&lt;br /&gt;
    $messageformat  = $fromform-&amp;gt;entry[&#039;format&#039;];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a user selects a file using the file picker, the file is initially stored in a draft file area, and a URL is inserted into the HTML in the editor that lets the person editing the content (but no one else) see the file.&lt;br /&gt;
&lt;br /&gt;
When the user submits the form, we then need to save the draft files to the correct place in permanent storage. (Just like you have to call $DB-&amp;gt;update_record(&#039;tablename&#039;, $data); to have the other parts of the form submission stored correctly.)&lt;br /&gt;
&lt;br /&gt;
The save_files_from_draft_area function and replace absolute links with internal relative links do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_save_draft_area_files($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                          $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $messagetext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $context-&amp;gt;id, &#039;component&#039;, &#039;proper_file_area&#039; and $entry-&amp;gt;id : correspond to the contextid, filearea and itemid columns in the [[File_API#Table:_files|files table]].&lt;br /&gt;
; $messagetext : this is the message text. As the files are saved to the real file area, the URLs in this content are rewritten.&lt;br /&gt;
&lt;br /&gt;
All URLs in content that point to files managed to the File API are converted to a form that starts &#039;@@PLUGINFILE@@/&#039; before the content is stored in the database. That is what we mean by rewriting.&lt;br /&gt;
&lt;br /&gt;
== File serving==&lt;br /&gt;
&lt;br /&gt;
=== Convert internal relative links to absolute links ===&lt;br /&gt;
&lt;br /&gt;
Before text content is displayed to the user, any URLs in the &#039;@@PLUGINFILE@@/&#039; form in the content need to be rewritten to the real URL where the user can access the files. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_rewrite_pluginfile_urls($messagetext, &#039;pluginfile.php&#039;,&lt;br /&gt;
        $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $messagetext : is the content containing the @@PLUGINFILE@@ URLs from the database.&lt;br /&gt;
; &#039;pluginfile.php&#039; : there are a number of different scripts that can serve files with different permissions checks. You need to specify which one to use.&lt;br /&gt;
; $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid : uniquely identifies the file area, as before.&lt;br /&gt;
&lt;br /&gt;
=== Implement file serving access control ===&lt;br /&gt;
&lt;br /&gt;
Attachments and embedded images should have the same access control like the text itself, in majority of cases these files are served using pluginfile.php. Access control is defined in &#039;&#039;module/lib.php&#039;&#039; file in function &#039;&#039;module_pluginfile()&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== File browsing support ==&lt;br /&gt;
Only owner of each file area is allowed to use low level File API function to access files, other parts of Moodle should use file browsing API.&lt;br /&gt;
&lt;br /&gt;
Activities may specify browsing support in own module/lib.php file by implementing functions module_get_file_areas() and module_get_file_info().&lt;br /&gt;
&lt;br /&gt;
== Upgrading your code ==&lt;br /&gt;
Here I will attempt to describe some simple steps you can take to upgrade your file-handling form elements from pre-2.0 code to 2.0. We will use the example of glossary, since it has been used above.&lt;br /&gt;
&lt;br /&gt;
=== Preparing your options ===&lt;br /&gt;
Unless you are happy with the defaults, you will need to define an array of options for each file-handling form element. You could define it at different places, but it&#039;s best to put it in one place and make the array(s) available to other files if they need it. In the majority of cases, this will be in a file like edit.php&lt;br /&gt;
&lt;br /&gt;
Previous code in mod/glossary/edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform =&amp;amp; new mod_glossary_entry_form(null, compact(&#039;cm&#039;, &#039;glossary&#039;, &#039;hook&#039;, &#039;mode&#039;, &#039;e&#039;, &#039;context&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$maxbytes = $course-&amp;gt;maxbytes;&lt;br /&gt;
// Could also use $CFG-&amp;gt;maxbytes if you are not coding within a course context&lt;br /&gt;
&lt;br /&gt;
$definitionoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;trusttext&#039;=&amp;gt;true,&lt;br /&gt;
                           &#039;context&#039;=&amp;gt;$context);&lt;br /&gt;
$attachmentoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that the data being passed to the form constructor have changed also, but this is not part of the file API changes, I just include them to avoid confusion.&lt;br /&gt;
&lt;br /&gt;
These options are for the htmleditor (definition field) and the filemanager (attachment field). They are used by a file called edit_form.php.&lt;br /&gt;
&lt;br /&gt;
=== Element preparation ===&lt;br /&gt;
Before we look at this, however, we need to &amp;quot;prepare&amp;quot; the elements so that they can correctly display existing embedded images and attached files when you are editing a record instead of just creating one. So, let&#039;s take the code we&#039;ve got so far in edit.php and add to it:&lt;br /&gt;
&lt;br /&gt;
Currently upgraded code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code with element preparation:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$entry = file_prepare_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                      &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_prepare_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                           &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* $entry in this case is simply a stdClass object which may either represent a new glossary entry or an existing one.&lt;br /&gt;
* $entry-&amp;gt;id must be the unique identifier for the current object. If we are creating a new entry, it will be null, but in all cases it must be defined.&lt;br /&gt;
* These two functions (file_prepare_standard_editor and file_prepare_standard_filemanager) are shortcuts functions that take care of some of the tedious setting up for you, but they make a couple of assumptions:&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; name the form element as {element}_editor or {element}_filemanager (see next section)&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; have at least the following fields in the database: {element} and {element}summary, as described earlier in this documentation&lt;br /&gt;
&lt;br /&gt;
We can now look at the upgrades needed in the form definition file.&lt;br /&gt;
&lt;br /&gt;
=== Form definition ===&lt;br /&gt;
Previous code in mod/glossary/edit_form.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;htmleditor&#039;, &#039;definition&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;),&lt;br /&gt;
                    array(&#039;rows&#039;=&amp;gt;20));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition&#039;, null, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;definition&#039;, array(&#039;writing&#039;, &#039;richtext&#039;), false, &#039;editorhelpbutton&#039;);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;format&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0,&lt;br /&gt;
                                             true, true, false));&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment&#039;, array(&#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                      &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$definitionoptions = $this-&amp;gt;_customdata[&#039;definitionoptions&#039;];&lt;br /&gt;
$attachmentoptions = $this-&amp;gt;_customdata[&#039;attachmentoptions&#039;];&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;definition_editor&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
                   $definitionoptions);&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition_editor&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition_editor&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachment_filemanager&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                   null, $attachmentoptions);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment_filemanager&#039;, array(&#039;attachment2&#039;,&lt;br /&gt;
                      get_string(&#039;attachment&#039;, &#039;glossary&#039;), &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the following:&lt;br /&gt;
* The format element and the help button are no longer required for the HTML editor element&lt;br /&gt;
* The name of the form element needs to be changed by adding &#039;_editor&#039; or &#039;_manager&#039; to the original name. This is a naming convention that is used by a couple of functions we will look at shortly&lt;br /&gt;
* Make sure $definitionoptions has context parameter, else system context is used and editor will not respect filter settings.&lt;br /&gt;
&lt;br /&gt;
=== Handling submitted data ===&lt;br /&gt;
The final step is to handle the submitted data properly, i.e. retrieve the files and save them to disk, associating them with the record we have just created (a glossary entry in our example). This happens in edit.php:&lt;br /&gt;
&lt;br /&gt;
Previous code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Section that updates an entry:&lt;br /&gt;
$todb-&amp;gt;id = $e;&lt;br /&gt;
$dir = glossary_file_area_name($todb);&lt;br /&gt;
if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
    $todb-&amp;gt;attachment = $newfilename;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Section that adds an entry:&lt;br /&gt;
if ($todb-&amp;gt;id = insert_record(&amp;quot;glossary_entries&amp;quot;, $todb)) {&lt;br /&gt;
    $e = $todb-&amp;gt;id;&lt;br /&gt;
    $dir = glossary_file_area_name($todb);&lt;br /&gt;
    if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
        set_field(&amp;quot;glossary_entries&amp;quot;, &amp;quot;attachment&amp;quot;, $newfilename, &amp;quot;id&amp;quot;, $todb-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// $todb was renamed to $entry, and the code was refactored &lt;br /&gt;
// so that the file-handling code is only used once for either an add or an update action.&lt;br /&gt;
// If an entry is being added, $DB-&amp;gt;insert() has already been called, so we have a valid $entry-&amp;gt;id&lt;br /&gt;
$entry = file_postupdate_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                         &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_postupdate_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                              &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
// store the updated value values&lt;br /&gt;
$DB-&amp;gt;update_record(&#039;glossary_entries&#039;, $entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* If you are adding a new record, you will still need to call update_record after calling the file_postupdate* functions&lt;br /&gt;
&lt;br /&gt;
=== Gotchas ===&lt;br /&gt;
A few things to keep in mind:&lt;br /&gt;
* Make sure that you instantiate the moodle form before any call to $OUTPUT-&amp;gt;header()&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Using the file API]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
* MDL-14589 - File API Meta issue&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=207748 Adding a text editor to a Moodle form]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=157953#p692822 Button actions in Moodle form]&lt;br /&gt;
&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51872</id>
		<title>Using the File API in Moodle forms</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51872"/>
		<updated>2017-02-10T13:10:26Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* See also links */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to get files from users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 all files are stored in a central database accessible via the [[File API|File API]], and every file is associated with a component and a &amp;quot;file area&amp;quot; in Moodle, such as a particular module.&lt;br /&gt;
&lt;br /&gt;
A common use case is to provide a form (using Moodle&#039;s [[lib/formslib.php|Forms API]]) which allows users to upload or import files as attachments or media embedded into HTML.&lt;br /&gt;
&lt;br /&gt;
Normally this works like this:&lt;br /&gt;
# User starts creation or re-edits an existing item in Moodle (eg forum post, resource, glossary entry etc)&lt;br /&gt;
# User presses some sort of button to browse for new files to attach or embed&lt;br /&gt;
# User sees our &amp;quot;Choose file...&amp;quot; dialog, which contains one or more repository instances. &lt;br /&gt;
# User chooses a file, the corresponding [[Repository plugins|Repository plugin]] takes care of copying the file into a &amp;quot;draft file area&amp;quot; within Moodle&lt;br /&gt;
# File appears in the text or as an attachment in the form.&lt;br /&gt;
# When the user hits save, the [[File API|File API]] is invoked to move the file from the draft file area into a permanent file area associated with that data &lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to interact with users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
If you just want to write code to manipulate Moodle files internally (without user input) then see [[File API]].&lt;br /&gt;
&lt;br /&gt;
==Form elements== &lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 there are three file-related form elements for interacting with users:&lt;br /&gt;
&lt;br /&gt;
# filemanager - the way to attach one or more files as a set&lt;br /&gt;
# editor - the way to specify a textarea with a HTML editor, and all the handling of images and movies within that HTML&lt;br /&gt;
# filepicker - a way to specify one file for the case when you want to process the file and throw it away &lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9 there were two other types which are now &#039;&#039;&#039;deprecated&#039;&#039;&#039; (they work, but please do not use these anymore)&lt;br /&gt;
# file - used to just allow a normal file upload from the desktop only.&lt;br /&gt;
# htmleditor - this old method of embedding a HTML editor in a textarea is not able to support repositories etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===filepicker===&lt;br /&gt;
&lt;br /&gt;
File picker (&#039;&#039;filepicker&#039;&#039;) is a direct replacement of the older &#039;&#039;file&#039;&#039; formslib element. &lt;br /&gt;
&lt;br /&gt;
It is intended for situations when you want the user to upload &#039;&#039;&#039;one&#039;&#039;&#039; file so you can process it and delete it, such as when you are importing data from a CSV file.&lt;br /&gt;
If you want a file that remains part of the Moodle storage and will reappear when you reopen the form, then you should use a filemanager instead (and restrict it to a single file, if necessary).&lt;br /&gt;
&lt;br /&gt;
==== Using the filepicker element ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null,&lt;br /&gt;
                   array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtain the chosen file ====&lt;br /&gt;
&lt;br /&gt;
To get the contents of the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content = $mform-&amp;gt;get_file_content(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To get the name of the chosen file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$name = $mform-&amp;gt;get_new_filename(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To save the chosen file to the server filesystem (such as to moodledata folder):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$success = $mform-&amp;gt;save_file(&#039;userfile&#039;, $fullpath, $override);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To store the chosen file in the Moodle files pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$storedfile = $mform-&amp;gt;save_stored_file(&#039;userfile&#039;, ...);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== filemanager ===&lt;br /&gt;
&lt;br /&gt;
The File Manager element improves on file picker by allowing you to manage more than one file.  It is expected that the files will be stored permanently for future use (such as forum and glossary attachments).&lt;br /&gt;
&lt;br /&gt;
==== Add file manager element ====&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachments&#039;, get_string(&#039;attachment&#039;, &#039;moodle&#039;), null,&lt;br /&gt;
                    array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;areamaxbytes&#039; =&amp;gt; 10485760, &#039;maxfiles&#039; =&amp;gt; 50,&lt;br /&gt;
                          &#039;accepted_types&#039; =&amp;gt; array(&#039;document&#039;), &#039;return_types&#039;=&amp;gt; FILE_INTERNAL | FILE_EXTERNAL));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are the fields for filemanager:&lt;br /&gt;
&lt;br /&gt;
;&#039;filemanager&#039;:This is a filemanager element :)&lt;br /&gt;
;elementname:The unique name of the element in the form&lt;br /&gt;
;elementlabel:The label string that users see &lt;br /&gt;
;attributes:(leave it as null)&lt;br /&gt;
;options: an array of further options for the filepicker (see below)&lt;br /&gt;
&lt;br /&gt;
The options array can contain:&lt;br /&gt;
&lt;br /&gt;
;subdirs:(Default 1) Are subdirectories allowed?  (true or false)&lt;br /&gt;
;maxbytes:(Default 0) Restricts the size of each individual file.&lt;br /&gt;
;areamaxbytes:(Default 0) Restricts the total size of all the files.&lt;br /&gt;
;maxfiles:(Default -1) Restricts the total number of files.&lt;br /&gt;
;accepted_types:(Default *) You can specify what file types are accepted by filemanager.  All current file types are listed in this file: [http://cvs.moodle.org/moodle/lib/filestorage/file_types.mm moodle/lib/filestorage/file_types.mm].  This is a [http://freemind.sourceforge.net/wiki/index.php/Main_Page freemind] file: if it is edited the changes will be immediately reflected in Moodle.&lt;br /&gt;
&lt;br /&gt;
As of 2.3 file_types.mm is no longer used, instead the file types are listed in &amp;lt;code&amp;gt;get_mimetypes_array()&amp;lt;/code&amp;gt; in filelib.php (https://github.com/moodle/moodle/blob/master/lib/classes/filetypes.php).&lt;br /&gt;
&lt;br /&gt;
Example usage:  &#039;&#039;&#039;array(&#039;audio&#039;, &#039;video&#039;, &#039;document&#039;)&#039;&#039;&#039;, you can include file extensions as well, for example: &#039;&#039;&#039;array(&#039;.txt&#039;, &#039;.jpg&#039;, &#039;audio&#039;)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Load existing files into draft area ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
    $entry = new stdClass;&lt;br /&gt;
    $entry-&amp;gt;id = null;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftitemid = file_get_submitted_draft_itemid(&#039;attachments&#039;);&lt;br /&gt;
&lt;br /&gt;
file_prepare_draft_area($draftitemid, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id,&lt;br /&gt;
                        array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
&lt;br /&gt;
$entry-&amp;gt;attachments = $draftitemid;&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Store updated set of files ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // ... store or update $entry&lt;br /&gt;
    file_save_draft_area_files($data-&amp;gt;attachments, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;,&lt;br /&gt;
                   $entry-&amp;gt;id, array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===editor===&lt;br /&gt;
There are two ways of using the editor element in code, the first one is easier but expects some standardized fields. The second method is more low level.&lt;br /&gt;
&lt;br /&gt;
====Simple use====&lt;br /&gt;
# name database fields: &#039;&#039;textfield&#039;&#039;, &#039;&#039;textfieldformat&#039;&#039; (and &#039;&#039;textfieldtrust&#039;&#039; if required)&lt;br /&gt;
# create options array.  note that context is the best, most local context you have available.&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$textfieldoptions = array(&#039;trusttext&#039;=&amp;gt;true, &#039;subdirs&#039;=&amp;gt;true, &#039;maxfiles&#039;=&amp;gt;$maxfiles, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;context&#039;=&amp;gt;$context);&amp;lt;/code&amp;gt;&lt;br /&gt;
# add editor &#039;&#039;textfield_editor&#039;&#039; to moodle form, pass options through custom data in form constructor, set $data-&amp;gt;id to null if data not exist yet&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;textfield_editor&#039;, get_string(&#039;fieldname&#039;, &#039;somemodule&#039;), null, $textfieldoptions);&amp;lt;/code&amp;gt;&lt;br /&gt;
# prepare data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_prepare_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
# get submitted data and after inserting/updating of data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_postupdate_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Real world examples are in mod/glossary/edit.php and mod/glossary/comment.php&lt;br /&gt;
&lt;br /&gt;
====Low level use====&lt;br /&gt;
&lt;br /&gt;
When using editor element you  need to preprocess and postprocess the data:&lt;br /&gt;
# detect if form was already submitted (usually means draft is area already exists) - &#039;&#039;file_get_submitted_draft_itemid()&#039;&#039;&lt;br /&gt;
# prepare draft file area, temporary storage of all files attached to the text - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# convert encoded relative links to absolute links - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# create form and set current data&lt;br /&gt;
# after submission the changed files must be merged back into original area - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
# absolute links have to be replaced by relative links - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=====Replace old htmleditor with editor=====&lt;br /&gt;
&lt;br /&gt;
The file picker has been integrated with with TinyMCE to make the editor element. This new element should support all types on editors and should be able to switch them on-the-fly. Instances of the old htmleditor element in your forms should be replaced by the new editor element, this may need adding of new format and trusttext columns. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;entry&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; EDITOR_UNLIMITED_FILES));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The editor element can take following options: maxfiles, maxbytes, subdirs and changeformat. Please note that the embedded files is optional feature and is not expected be used everywhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the editor element now includes text format option. You should no longer use the separate format element type.&lt;br /&gt;
&lt;br /&gt;
=====Prepare current data - text and files=====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
  $entry = new object();&lt;br /&gt;
  $entry-&amp;gt;id = null;&lt;br /&gt;
  $entry-&amp;gt;definition = &#039;&#039;;&lt;br /&gt;
  $entry-&amp;gt;format = FORMAT_HTML;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftid_editor = file_get_submitted_draft_itemid(&#039;entry&#039;);&lt;br /&gt;
$currenttext = file_prepare_draft_area($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                       $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $entry-&amp;gt;definition);&lt;br /&gt;
$entry-&amp;gt;entry = array(&#039;text&#039;=&amp;gt;$currenttext, &#039;format&#039;=&amp;gt;$entry-&amp;gt;format, &#039;itemid&#039;=&amp;gt;$draftid_editor);&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are multiple files, they will share the same itemid.&lt;br /&gt;
&lt;br /&gt;
=====Obtain text, format and save draft files=====&lt;br /&gt;
&lt;br /&gt;
To retrieve editor content, you need to use following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // content of editor&lt;br /&gt;
    $messagetext = $fromform-&amp;gt;entry[&#039;text&#039;];&lt;br /&gt;
    // format of content&lt;br /&gt;
    $messageformat  = $fromform-&amp;gt;entry[&#039;format&#039;];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a user selects a file using the file picker, the file is initially stored in a draft file area, and a URL is inserted into the HTML in the editor that lets the person editing the content (but no one else) see the file.&lt;br /&gt;
&lt;br /&gt;
When the user submits the form, we then need to save the draft files to the correct place in permanent storage. (Just like you have to call $DB-&amp;gt;update_record(&#039;tablename&#039;, $data); to have the other parts of the form submission stored correctly.)&lt;br /&gt;
&lt;br /&gt;
The save_files_from_draft_area function and replace absolute links with internal relative links do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_save_draft_area_files($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                          $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $messagetext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $context-&amp;gt;id, &#039;component&#039;, &#039;proper_file_area&#039; and $entry-&amp;gt;id : correspond to the contextid, filearea and itemid columns in the [[File_API#Table:_files|files table]].&lt;br /&gt;
; $messagetext : this is the message text. As the files are saved to the real file area, the URLs in this content are rewritten.&lt;br /&gt;
&lt;br /&gt;
All URLs in content that point to files managed to the File API are converted to a form that starts &#039;@@PLUGINFILE@@/&#039; before the content is stored in the database. That is what we mean by rewriting.&lt;br /&gt;
&lt;br /&gt;
== File serving==&lt;br /&gt;
&lt;br /&gt;
=== Convert internal relative links to absolute links ===&lt;br /&gt;
&lt;br /&gt;
Before text content is displayed to the user, any URLs in the &#039;@@PLUGINFILE@@/&#039; form in the content need to be rewritten to the real URL where the user can access the files. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_rewrite_pluginfile_urls($messagetext, &#039;pluginfile.php&#039;,&lt;br /&gt;
        $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $messagetext : is the content containing the @@PLUGINFILE@@ URLs from the database.&lt;br /&gt;
; &#039;pluginfile.php&#039; : there are a number of different scripts that can serve files with different permissions checks. You need to specify which one to use.&lt;br /&gt;
; $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid : uniquely identifies the file area, as before.&lt;br /&gt;
&lt;br /&gt;
=== Implement file serving access control ===&lt;br /&gt;
&lt;br /&gt;
Attachments and embedded images should have the same access control like the text itself, in majority of cases these files are served using pluginfile.php. Access control is defined in &#039;&#039;module/lib.php&#039;&#039; file in function &#039;&#039;module_pluginfile()&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== File browsing support ==&lt;br /&gt;
Only owner of each file area is allowed to use low level File API function to access files, other parts of Moodle should use file browsing API.&lt;br /&gt;
&lt;br /&gt;
Activities may specify browsing support in own module/lib.php file by implementing functions module_get_file_areas() and module_get_file_info().&lt;br /&gt;
&lt;br /&gt;
== Upgrading your code ==&lt;br /&gt;
Here I will attempt to describe some simple steps you can take to upgrade your file-handling form elements from pre-2.0 code to 2.0. We will use the example of glossary, since it has been used above.&lt;br /&gt;
&lt;br /&gt;
=== Preparing your options ===&lt;br /&gt;
Unless you are happy with the defaults, you will need to define an array of options for each file-handling form element. You could define it at different places, but it&#039;s best to put it in one place and make the array(s) available to other files if they need it. In the majority of cases, this will be in a file like edit.php&lt;br /&gt;
&lt;br /&gt;
Previous code in mod/glossary/edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform =&amp;amp; new mod_glossary_entry_form(null, compact(&#039;cm&#039;, &#039;glossary&#039;, &#039;hook&#039;, &#039;mode&#039;, &#039;e&#039;, &#039;context&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$maxbytes = $course-&amp;gt;maxbytes;&lt;br /&gt;
// Could also use $CFG-&amp;gt;maxbytes if you are not coding within a course context&lt;br /&gt;
&lt;br /&gt;
$definitionoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;trusttext&#039;=&amp;gt;true,&lt;br /&gt;
                           &#039;context&#039;=&amp;gt;$context);&lt;br /&gt;
$attachmentoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that the data being passed to the form constructor have changed also, but this is not part of the file API changes, I just include them to avoid confusion.&lt;br /&gt;
&lt;br /&gt;
These options are for the htmleditor (definition field) and the filemanager (attachment field). They are used by a file called edit_form.php.&lt;br /&gt;
&lt;br /&gt;
=== Element preparation ===&lt;br /&gt;
Before we look at this, however, we need to &amp;quot;prepare&amp;quot; the elements so that they can correctly display existing embedded images and attached files when you are editing a record instead of just creating one. So, let&#039;s take the code we&#039;ve got so far in edit.php and add to it:&lt;br /&gt;
&lt;br /&gt;
Currently upgraded code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code with element preparation:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$entry = file_prepare_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                      &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_prepare_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                           &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* $entry in this case is simply a stdClass object which may either represent a new glossary entry or an existing one.&lt;br /&gt;
* $entry-&amp;gt;id must be the unique identifier for the current object. If we are creating a new entry, it will be null, but in all cases it must be defined.&lt;br /&gt;
* These two functions (file_prepare_standard_editor and file_prepare_standard_filemanager) are shortcuts functions that take care of some of the tedious setting up for you, but they make a couple of assumptions:&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; name the form element as {element}_editor or {element}_filemanager (see next section)&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; have at least the following fields in the database: {element} and {element}summary, as described earlier in this documentation&lt;br /&gt;
&lt;br /&gt;
We can now look at the upgrades needed in the form definition file.&lt;br /&gt;
&lt;br /&gt;
=== Form definition ===&lt;br /&gt;
Previous code in mod/glossary/edit_form.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;htmleditor&#039;, &#039;definition&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;),&lt;br /&gt;
                    array(&#039;rows&#039;=&amp;gt;20));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition&#039;, null, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;definition&#039;, array(&#039;writing&#039;, &#039;richtext&#039;), false, &#039;editorhelpbutton&#039;);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;format&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0,&lt;br /&gt;
                                             true, true, false));&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment&#039;, array(&#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                      &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$definitionoptions = $this-&amp;gt;_customdata[&#039;definitionoptions&#039;];&lt;br /&gt;
$attachmentoptions = $this-&amp;gt;_customdata[&#039;attachmentoptions&#039;];&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;definition_editor&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
                   $definitionoptions);&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition_editor&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition_editor&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachment_filemanager&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                   null, $attachmentoptions);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment_filemanager&#039;, array(&#039;attachment2&#039;,&lt;br /&gt;
                      get_string(&#039;attachment&#039;, &#039;glossary&#039;), &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the following:&lt;br /&gt;
* The format element and the help button are no longer required for the HTML editor element&lt;br /&gt;
* The name of the form element needs to be changed by adding &#039;_editor&#039; or &#039;_manager&#039; to the original name. This is a naming convention that is used by a couple of functions we will look at shortly&lt;br /&gt;
* Make sure $definitionoptions has context parameter, else system context is used and editor will not respect filter settings.&lt;br /&gt;
&lt;br /&gt;
=== Handling submitted data ===&lt;br /&gt;
The final step is to handle the submitted data properly, i.e. retrieve the files and save them to disk, associating them with the record we have just created (a glossary entry in our example). This happens in edit.php:&lt;br /&gt;
&lt;br /&gt;
Previous code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Section that updates an entry:&lt;br /&gt;
$todb-&amp;gt;id = $e;&lt;br /&gt;
$dir = glossary_file_area_name($todb);&lt;br /&gt;
if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
    $todb-&amp;gt;attachment = $newfilename;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Section that adds an entry:&lt;br /&gt;
if ($todb-&amp;gt;id = insert_record(&amp;quot;glossary_entries&amp;quot;, $todb)) {&lt;br /&gt;
    $e = $todb-&amp;gt;id;&lt;br /&gt;
    $dir = glossary_file_area_name($todb);&lt;br /&gt;
    if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
        set_field(&amp;quot;glossary_entries&amp;quot;, &amp;quot;attachment&amp;quot;, $newfilename, &amp;quot;id&amp;quot;, $todb-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// $todb was renamed to $entry, and the code was refactored &lt;br /&gt;
// so that the file-handling code is only used once for either an add or an update action.&lt;br /&gt;
// If an entry is being added, $DB-&amp;gt;insert() has already been called, so we have a valid $entry-&amp;gt;id&lt;br /&gt;
$entry = file_postupdate_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                         &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_postupdate_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                              &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
// store the updated value values&lt;br /&gt;
$DB-&amp;gt;update_record(&#039;glossary_entries&#039;, $entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* If you are adding a new record, you will still need to call update_record after calling the file_postupdate* functions&lt;br /&gt;
&lt;br /&gt;
=== Gotchas ===&lt;br /&gt;
A few things to keep in mind:&lt;br /&gt;
* Make sure that you instantiate the moodle form before any call to $OUTPUT-&amp;gt;header()&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Using the file API]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
* MDL-14589 - File API Meta issue&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=207748 Adding a text editor to a Moodle form]&lt;br /&gt;
* [https://moodle.org/mod/forum/discuss.php?d=157953#p692822 Button actions in moodle form]&lt;br /&gt;
&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51863</id>
		<title>Using the File API in Moodle forms</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51863"/>
		<updated>2017-02-08T09:14:17Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Simple use - wiki formatting */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to get files from users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 all files are stored in a central database accessible via the [[File API|File API]], and every file is associated with a component and a &amp;quot;file area&amp;quot; in Moodle, such as a particular module.&lt;br /&gt;
&lt;br /&gt;
A common use case is to provide a form (using Moodle&#039;s [[lib/formslib.php|Forms API]]) which allows users to upload or import files as attachments or media embedded into HTML.&lt;br /&gt;
&lt;br /&gt;
Normally this works like this:&lt;br /&gt;
# User starts creation or re-edits an existing item in Moodle (eg forum post, resource, glossary entry etc)&lt;br /&gt;
# User presses some sort of button to browse for new files to attach or embed&lt;br /&gt;
# User sees our &amp;quot;Choose file...&amp;quot; dialog, which contains one or more repository instances. &lt;br /&gt;
# User chooses a file, the corresponding [[Repository plugins|Repository plugin]] takes care of copying the file into a &amp;quot;draft file area&amp;quot; within Moodle&lt;br /&gt;
# File appears in the text or as an attachment in the form.&lt;br /&gt;
# When the user hits save, the [[File API|File API]] is invoked to move the file from the draft file area into a permanent file area associated with that data &lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to interact with users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
If you just want to write code to manipulate Moodle files internally (without user input) then see [[File API]].&lt;br /&gt;
&lt;br /&gt;
==Form elements== &lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 there are three file-related form elements for interacting with users:&lt;br /&gt;
&lt;br /&gt;
# filemanager - the way to attach one or more files as a set&lt;br /&gt;
# editor - the way to specify a textarea with a HTML editor, and all the handling of images and movies within that HTML&lt;br /&gt;
# filepicker - a way to specify one file for the case when you want to process the file and throw it away &lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9 there were two other types which are now &#039;&#039;&#039;deprecated&#039;&#039;&#039; (they work, but please do not use these anymore)&lt;br /&gt;
# file - used to just allow a normal file upload from the desktop only.&lt;br /&gt;
# htmleditor - this old method of embedding a HTML editor in a textarea is not able to support repositories etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===filepicker===&lt;br /&gt;
&lt;br /&gt;
File picker (&#039;&#039;filepicker&#039;&#039;) is a direct replacement of the older &#039;&#039;file&#039;&#039; formslib element. &lt;br /&gt;
&lt;br /&gt;
It is intended for situations when you want the user to upload &#039;&#039;&#039;one&#039;&#039;&#039; file so you can process it and delete it, such as when you are importing data from a CSV file.&lt;br /&gt;
If you want a file that remains part of the Moodle storage and will reappear when you reopen the form, then you should use a filemanager instead (and restrict it to a single file, if necessary).&lt;br /&gt;
&lt;br /&gt;
==== Using the filepicker element ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null,&lt;br /&gt;
                   array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtain the chosen file ====&lt;br /&gt;
&lt;br /&gt;
To get the contents of the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content = $mform-&amp;gt;get_file_content(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To get the name of the chosen file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$name = $mform-&amp;gt;get_new_filename(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To save the chosen file to the server filesystem (such as to moodledata folder):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$success = $mform-&amp;gt;save_file(&#039;userfile&#039;, $fullpath, $override);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To store the chosen file in the Moodle files pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$storedfile = $mform-&amp;gt;save_stored_file(&#039;userfile&#039;, ...);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== filemanager ===&lt;br /&gt;
&lt;br /&gt;
The File Manager element improves on file picker by allowing you to manage more than one file.  It is expected that the files will be stored permanently for future use (such as forum and glossary attachments).&lt;br /&gt;
&lt;br /&gt;
==== Add file manager element ====&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachments&#039;, get_string(&#039;attachment&#039;, &#039;moodle&#039;), null,&lt;br /&gt;
                    array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;areamaxbytes&#039; =&amp;gt; 10485760, &#039;maxfiles&#039; =&amp;gt; 50,&lt;br /&gt;
                          &#039;accepted_types&#039; =&amp;gt; array(&#039;document&#039;), &#039;return_types&#039;=&amp;gt; FILE_INTERNAL | FILE_EXTERNAL));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are the fields for filemanager:&lt;br /&gt;
&lt;br /&gt;
;&#039;filemanager&#039;:This is a filemanager element :)&lt;br /&gt;
;elementname:The unique name of the element in the form&lt;br /&gt;
;elementlabel:The label string that users see &lt;br /&gt;
;attributes:(leave it as null)&lt;br /&gt;
;options: an array of further options for the filepicker (see below)&lt;br /&gt;
&lt;br /&gt;
The options array can contain:&lt;br /&gt;
&lt;br /&gt;
;subdirs:(Default 1) Are subdirectories allowed?  (true or false)&lt;br /&gt;
;maxbytes:(Default 0) Restricts the size of each individual file.&lt;br /&gt;
;areamaxbytes:(Default 0) Restricts the total size of all the files.&lt;br /&gt;
;maxfiles:(Default -1) Restricts the total number of files.&lt;br /&gt;
;accepted_types:(Default *) You can specify what file types are accepted by filemanager.  All current file types are listed in this file: [http://cvs.moodle.org/moodle/lib/filestorage/file_types.mm moodle/lib/filestorage/file_types.mm].  This is a [http://freemind.sourceforge.net/wiki/index.php/Main_Page freemind] file: if it is edited the changes will be immediately reflected in Moodle.&lt;br /&gt;
&lt;br /&gt;
As of 2.3 file_types.mm is no longer used, instead the file types are listed in &amp;lt;code&amp;gt;get_mimetypes_array()&amp;lt;/code&amp;gt; in filelib.php (https://github.com/moodle/moodle/blob/master/lib/classes/filetypes.php).&lt;br /&gt;
&lt;br /&gt;
Example usage:  &#039;&#039;&#039;array(&#039;audio&#039;, &#039;video&#039;, &#039;document&#039;)&#039;&#039;&#039;, you can include file extensions as well, for example: &#039;&#039;&#039;array(&#039;.txt&#039;, &#039;.jpg&#039;, &#039;audio&#039;)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Load existing files into draft area ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
    $entry = new stdClass;&lt;br /&gt;
    $entry-&amp;gt;id = null;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftitemid = file_get_submitted_draft_itemid(&#039;attachments&#039;);&lt;br /&gt;
&lt;br /&gt;
file_prepare_draft_area($draftitemid, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id,&lt;br /&gt;
                        array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
&lt;br /&gt;
$entry-&amp;gt;attachments = $draftitemid;&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Store updated set of files ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // ... store or update $entry&lt;br /&gt;
    file_save_draft_area_files($data-&amp;gt;attachments, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;,&lt;br /&gt;
                   $entry-&amp;gt;id, array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===editor===&lt;br /&gt;
There are two ways of using the editor element in code, the first one is easier but expects some standardized fields. The second method is more low level.&lt;br /&gt;
&lt;br /&gt;
====Simple use====&lt;br /&gt;
# name database fields: &#039;&#039;textfield&#039;&#039;, &#039;&#039;textfieldformat&#039;&#039; (and &#039;&#039;textfieldtrust&#039;&#039; if required)&lt;br /&gt;
# create options array.  note that context is the best, most local context you have available.&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$textfieldoptions = array(&#039;trusttext&#039;=&amp;gt;true, &#039;subdirs&#039;=&amp;gt;true, &#039;maxfiles&#039;=&amp;gt;$maxfiles, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;context&#039;=&amp;gt;$context);&amp;lt;/code&amp;gt;&lt;br /&gt;
# add editor &#039;&#039;textfield_editor&#039;&#039; to moodle form, pass options through custom data in form constructor, set $data-&amp;gt;id to null if data not exist yet&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;textfield_editor&#039;, get_string(&#039;fieldname&#039;, &#039;somemodule&#039;), null, $textfieldoptions);&amp;lt;/code&amp;gt;&lt;br /&gt;
# prepare data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_prepare_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
# get submitted data and after inserting/updating of data&lt;br /&gt;
#:&amp;lt;code php&amp;gt;$data = file_postupdate_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context, &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Real world examples are in mod/glossary/edit.php and mod/glossary/comment.php&lt;br /&gt;
&lt;br /&gt;
====Low level use====&lt;br /&gt;
&lt;br /&gt;
When using editor element you  need to preprocess and postprocess the data:&lt;br /&gt;
# detect if form was already submitted (usually means draft is area already exists) - &#039;&#039;file_get_submitted_draft_itemid()&#039;&#039;&lt;br /&gt;
# prepare draft file area, temporary storage of all files attached to the text - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# convert encoded relative links to absolute links - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# create form and set current data&lt;br /&gt;
# after submission the changed files must be merged back into original area - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
# absolute links have to be replaced by relative links - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=====Replace old htmleditor with editor=====&lt;br /&gt;
&lt;br /&gt;
The file picker has been integrated with with TinyMCE to make the editor element. This new element should support all types on editors and should be able to switch them on-the-fly. Instances of the old htmleditor element in your forms should be replaced by the new editor element, this may need adding of new format and trusttext columns. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;entry&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; EDITOR_UNLIMITED_FILES));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The editor element can take following options: maxfiles, maxbytes, subdirs and changeformat. Please note that the embedded files is optional feature and is not expected be used everywhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the editor element now includes text format option. You should no longer use the separate format element type.&lt;br /&gt;
&lt;br /&gt;
=====Prepare current data - text and files=====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
  $entry = new object();&lt;br /&gt;
  $entry-&amp;gt;id = null;&lt;br /&gt;
  $entry-&amp;gt;definition = &#039;&#039;;&lt;br /&gt;
  $entry-&amp;gt;format = FORMAT_HTML;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftid_editor = file_get_submitted_draft_itemid(&#039;entry&#039;);&lt;br /&gt;
$currenttext = file_prepare_draft_area($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                       $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $entry-&amp;gt;definition);&lt;br /&gt;
$entry-&amp;gt;entry = array(&#039;text&#039;=&amp;gt;$currenttext, &#039;format&#039;=&amp;gt;$entry-&amp;gt;format, &#039;itemid&#039;=&amp;gt;$draftid_editor);&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are multiple files, they will share the same itemid.&lt;br /&gt;
&lt;br /&gt;
=====Obtain text, format and save draft files=====&lt;br /&gt;
&lt;br /&gt;
To retrieve editor content, you need to use following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // content of editor&lt;br /&gt;
    $messagetext = $fromform-&amp;gt;entry[&#039;text&#039;];&lt;br /&gt;
    // format of content&lt;br /&gt;
    $messageformat  = $fromform-&amp;gt;entry[&#039;format&#039;];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a user selects a file using the file picker, the file is initially stored in a draft file area, and a URL is inserted into the HTML in the editor that lets the person editing the content (but no one else) see the file.&lt;br /&gt;
&lt;br /&gt;
When the user submits the form, we then need to save the draft files to the correct place in permanent storage. (Just like you have to call $DB-&amp;gt;update_record(&#039;tablename&#039;, $data); to have the other parts of the form submission stored correctly.)&lt;br /&gt;
&lt;br /&gt;
The save_files_from_draft_area function and replace absolute links with internal relative links do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_save_draft_area_files($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                          $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $messagetext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $context-&amp;gt;id, &#039;component&#039;, &#039;proper_file_area&#039; and $entry-&amp;gt;id : correspond to the contextid, filearea and itemid columns in the [[File_API#Table:_files|files table]].&lt;br /&gt;
; $messagetext : this is the message text. As the files are saved to the real file area, the URLs in this content are rewritten.&lt;br /&gt;
&lt;br /&gt;
All URLs in content that point to files managed to the File API are converted to a form that starts &#039;@@PLUGINFILE@@/&#039; before the content is stored in the database. That is what we mean by rewriting.&lt;br /&gt;
&lt;br /&gt;
== File serving==&lt;br /&gt;
&lt;br /&gt;
=== Convert internal relative links to absolute links ===&lt;br /&gt;
&lt;br /&gt;
Before text content is displayed to the user, any URLs in the &#039;@@PLUGINFILE@@/&#039; form in the content need to be rewritten to the real URL where the user can access the files. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_rewrite_pluginfile_urls($messagetext, &#039;pluginfile.php&#039;,&lt;br /&gt;
        $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $messagetext : is the content containing the @@PLUGINFILE@@ URLs from the database.&lt;br /&gt;
; &#039;pluginfile.php&#039; : there are a number of different scripts that can serve files with different permissions checks. You need to specify which one to use.&lt;br /&gt;
; $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid : uniquely identifies the file area, as before.&lt;br /&gt;
&lt;br /&gt;
=== Implement file serving access control ===&lt;br /&gt;
&lt;br /&gt;
Attachments and embedded images should have the same access control like the text itself, in majority of cases these files are served using pluginfile.php. Access control is defined in &#039;&#039;module/lib.php&#039;&#039; file in function &#039;&#039;module_pluginfile()&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== File browsing support ==&lt;br /&gt;
Only owner of each file area is allowed to use low level File API function to access files, other parts of Moodle should use file browsing API.&lt;br /&gt;
&lt;br /&gt;
Activities may specify browsing support in own module/lib.php file by implementing functions module_get_file_areas() and module_get_file_info().&lt;br /&gt;
&lt;br /&gt;
== Upgrading your code ==&lt;br /&gt;
Here I will attempt to describe some simple steps you can take to upgrade your file-handling form elements from pre-2.0 code to 2.0. We will use the example of glossary, since it has been used above.&lt;br /&gt;
&lt;br /&gt;
=== Preparing your options ===&lt;br /&gt;
Unless you are happy with the defaults, you will need to define an array of options for each file-handling form element. You could define it at different places, but it&#039;s best to put it in one place and make the array(s) available to other files if they need it. In the majority of cases, this will be in a file like edit.php&lt;br /&gt;
&lt;br /&gt;
Previous code in mod/glossary/edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform =&amp;amp; new mod_glossary_entry_form(null, compact(&#039;cm&#039;, &#039;glossary&#039;, &#039;hook&#039;, &#039;mode&#039;, &#039;e&#039;, &#039;context&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$maxbytes = $course-&amp;gt;maxbytes;&lt;br /&gt;
// Could also use $CFG-&amp;gt;maxbytes if you are not coding within a course context&lt;br /&gt;
&lt;br /&gt;
$definitionoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;trusttext&#039;=&amp;gt;true,&lt;br /&gt;
                           &#039;context&#039;=&amp;gt;$context);&lt;br /&gt;
$attachmentoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that the data being passed to the form constructor have changed also, but this is not part of the file API changes, I just include them to avoid confusion.&lt;br /&gt;
&lt;br /&gt;
These options are for the htmleditor (definition field) and the filemanager (attachment field). They are used by a file called edit_form.php.&lt;br /&gt;
&lt;br /&gt;
=== Element preparation ===&lt;br /&gt;
Before we look at this, however, we need to &amp;quot;prepare&amp;quot; the elements so that they can correctly display existing embedded images and attached files when you are editing a record instead of just creating one. So, let&#039;s take the code we&#039;ve got so far in edit.php and add to it:&lt;br /&gt;
&lt;br /&gt;
Currently upgraded code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code with element preparation:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$entry = file_prepare_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                      &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_prepare_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                           &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* $entry in this case is simply a stdClass object which may either represent a new glossary entry or an existing one.&lt;br /&gt;
* $entry-&amp;gt;id must be the unique identifier for the current object. If we are creating a new entry, it will be null, but in all cases it must be defined.&lt;br /&gt;
* These two functions (file_prepare_standard_editor and file_prepare_standard_filemanager) are shortcuts functions that take care of some of the tedious setting up for you, but they make a couple of assumptions:&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; name the form element as {element}_editor or {element}_filemanager (see next section)&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; have at least the following fields in the database: {element} and {element}summary, as described earlier in this documentation&lt;br /&gt;
&lt;br /&gt;
We can now look at the upgrades needed in the form definition file.&lt;br /&gt;
&lt;br /&gt;
=== Form definition ===&lt;br /&gt;
Previous code in mod/glossary/edit_form.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;htmleditor&#039;, &#039;definition&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;),&lt;br /&gt;
                    array(&#039;rows&#039;=&amp;gt;20));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition&#039;, null, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;definition&#039;, array(&#039;writing&#039;, &#039;richtext&#039;), false, &#039;editorhelpbutton&#039;);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;format&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0,&lt;br /&gt;
                                             true, true, false));&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment&#039;, array(&#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                      &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$definitionoptions = $this-&amp;gt;_customdata[&#039;definitionoptions&#039;];&lt;br /&gt;
$attachmentoptions = $this-&amp;gt;_customdata[&#039;attachmentoptions&#039;];&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;definition_editor&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
                   $definitionoptions);&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition_editor&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition_editor&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachment_filemanager&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                   null, $attachmentoptions);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment_filemanager&#039;, array(&#039;attachment2&#039;,&lt;br /&gt;
                      get_string(&#039;attachment&#039;, &#039;glossary&#039;), &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the following:&lt;br /&gt;
* The format element and the help button are no longer required for the HTML editor element&lt;br /&gt;
* The name of the form element needs to be changed by adding &#039;_editor&#039; or &#039;_manager&#039; to the original name. This is a naming convention that is used by a couple of functions we will look at shortly&lt;br /&gt;
* Make sure $definitionoptions has context parameter, else system context is used and editor will not respect filter settings.&lt;br /&gt;
&lt;br /&gt;
=== Handling submitted data ===&lt;br /&gt;
The final step is to handle the submitted data properly, i.e. retrieve the files and save them to disk, associating them with the record we have just created (a glossary entry in our example). This happens in edit.php:&lt;br /&gt;
&lt;br /&gt;
Previous code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Section that updates an entry:&lt;br /&gt;
$todb-&amp;gt;id = $e;&lt;br /&gt;
$dir = glossary_file_area_name($todb);&lt;br /&gt;
if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
    $todb-&amp;gt;attachment = $newfilename;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Section that adds an entry:&lt;br /&gt;
if ($todb-&amp;gt;id = insert_record(&amp;quot;glossary_entries&amp;quot;, $todb)) {&lt;br /&gt;
    $e = $todb-&amp;gt;id;&lt;br /&gt;
    $dir = glossary_file_area_name($todb);&lt;br /&gt;
    if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
        set_field(&amp;quot;glossary_entries&amp;quot;, &amp;quot;attachment&amp;quot;, $newfilename, &amp;quot;id&amp;quot;, $todb-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// $todb was renamed to $entry, and the code was refactored &lt;br /&gt;
// so that the file-handling code is only used once for either an add or an update action.&lt;br /&gt;
// If an entry is being added, $DB-&amp;gt;insert() has already been called, so we have a valid $entry-&amp;gt;id&lt;br /&gt;
$entry = file_postupdate_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                         &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_postupdate_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                              &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
// store the updated value values&lt;br /&gt;
$DB-&amp;gt;update_record(&#039;glossary_entries&#039;, $entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* If you are adding a new record, you will still need to call update_record after calling the file_postupdate* functions&lt;br /&gt;
&lt;br /&gt;
=== Gotchas ===&lt;br /&gt;
A few things to keep in mind:&lt;br /&gt;
* Make sure that you instantiate the moodle form before any call to $OUTPUT-&amp;gt;header()&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Using the file API]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
* MDL-14589 - File API Meta issue&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=207748 Adding a text editor to a Moodle form]&lt;br /&gt;
&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51862</id>
		<title>Using the File API in Moodle forms</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Using_the_File_API_in_Moodle_forms&amp;diff=51862"/>
		<updated>2017-02-08T08:17:36Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* filepicker - usage info */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to get files from users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 all files are stored in a central database accessible via the [[File API|File API]], and every file is associated with a component and a &amp;quot;file area&amp;quot; in Moodle, such as a particular module.&lt;br /&gt;
&lt;br /&gt;
A common use case is to provide a form (using Moodle&#039;s [[lib/formslib.php|Forms API]]) which allows users to upload or import files as attachments or media embedded into HTML.&lt;br /&gt;
&lt;br /&gt;
Normally this works like this:&lt;br /&gt;
# User starts creation or re-edits an existing item in Moodle (eg forum post, resource, glossary entry etc)&lt;br /&gt;
# User presses some sort of button to browse for new files to attach or embed&lt;br /&gt;
# User sees our &amp;quot;Choose file...&amp;quot; dialog, which contains one or more repository instances. &lt;br /&gt;
# User chooses a file, the corresponding [[Repository plugins|Repository plugin]] takes care of copying the file into a &amp;quot;draft file area&amp;quot; within Moodle&lt;br /&gt;
# File appears in the text or as an attachment in the form.&lt;br /&gt;
# When the user hits save, the [[File API|File API]] is invoked to move the file from the draft file area into a permanent file area associated with that data &lt;br /&gt;
&lt;br /&gt;
This document shows you exactly how to use Moodle forms to interact with users in a standard and secure way.&lt;br /&gt;
&lt;br /&gt;
If you just want to write code to manipulate Moodle files internally (without user input) then see [[File API]].&lt;br /&gt;
&lt;br /&gt;
==Form elements== &lt;br /&gt;
&lt;br /&gt;
In Moodle 2.0 there are three file-related form elements for interacting with users:&lt;br /&gt;
&lt;br /&gt;
# filemanager - the way to attach one or more files as a set&lt;br /&gt;
# editor - the way to specify a textarea with a HTML editor, and all the handling of images and movies within that HTML&lt;br /&gt;
# filepicker - a way to specify one file for the case when you want to process the file and throw it away &lt;br /&gt;
&lt;br /&gt;
In Moodle 1.9 there were two other types which are now &#039;&#039;&#039;deprecated&#039;&#039;&#039; (they work, but please do not use these anymore)&lt;br /&gt;
# file - used to just allow a normal file upload from the desktop only.&lt;br /&gt;
# htmleditor - this old method of embedding a HTML editor in a textarea is not able to support repositories etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===filepicker===&lt;br /&gt;
&lt;br /&gt;
File picker (&#039;&#039;filepicker&#039;&#039;) is a direct replacement of the older &#039;&#039;file&#039;&#039; formslib element. &lt;br /&gt;
&lt;br /&gt;
It is intended for situations when you want the user to upload &#039;&#039;&#039;one&#039;&#039;&#039; file so you can process it and delete it, such as when you are importing data from a CSV file.&lt;br /&gt;
If you want a file that remains part of the Moodle storage and will reappear when you reopen the form, then you should use a filemanager instead (and restrict it to a single file, if necessary).&lt;br /&gt;
&lt;br /&gt;
==== Using the filepicker element ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filepicker&#039;, &#039;userfile&#039;, get_string(&#039;file&#039;), null,&lt;br /&gt;
                   array(&#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;accepted_types&#039; =&amp;gt; &#039;*&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Obtain the chosen file ====&lt;br /&gt;
&lt;br /&gt;
To get the contents of the file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$content = $mform-&amp;gt;get_file_content(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To get the name of the chosen file:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$name = $mform-&amp;gt;get_new_filename(&#039;userfile&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To save the chosen file to the server filesystem (such as to moodledata folder):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$success = $mform-&amp;gt;save_file(&#039;userfile&#039;, $fullpath, $override);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
To store the chosen file in the Moodle files pool:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$storedfile = $mform-&amp;gt;save_stored_file(&#039;userfile&#039;, ...);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== filemanager ===&lt;br /&gt;
&lt;br /&gt;
The File Manager element improves on file picker by allowing you to manage more than one file.  It is expected that the files will be stored permanently for future use (such as forum and glossary attachments).&lt;br /&gt;
&lt;br /&gt;
==== Add file manager element ====&lt;br /&gt;
&lt;br /&gt;
Example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachments&#039;, get_string(&#039;attachment&#039;, &#039;moodle&#039;), null,&lt;br /&gt;
                    array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;areamaxbytes&#039; =&amp;gt; 10485760, &#039;maxfiles&#039; =&amp;gt; 50,&lt;br /&gt;
                          &#039;accepted_types&#039; =&amp;gt; array(&#039;document&#039;), &#039;return_types&#039;=&amp;gt; FILE_INTERNAL | FILE_EXTERNAL));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Here are the fields for filemanager:&lt;br /&gt;
&lt;br /&gt;
;&#039;filemanager&#039;:This is a filemanager element :)&lt;br /&gt;
;elementname:The unique name of the element in the form&lt;br /&gt;
;elementlabel:The label string that users see &lt;br /&gt;
;attributes:(leave it as null)&lt;br /&gt;
;options: an array of further options for the filepicker (see below)&lt;br /&gt;
&lt;br /&gt;
The options array can contain:&lt;br /&gt;
&lt;br /&gt;
;subdirs:(Default 1) Are subdirectories allowed?  (true or false)&lt;br /&gt;
;maxbytes:(Default 0) Restricts the size of each individual file.&lt;br /&gt;
;areamaxbytes:(Default 0) Restricts the total size of all the files.&lt;br /&gt;
;maxfiles:(Default -1) Restricts the total number of files.&lt;br /&gt;
;accepted_types:(Default *) You can specify what file types are accepted by filemanager.  All current file types are listed in this file: [http://cvs.moodle.org/moodle/lib/filestorage/file_types.mm moodle/lib/filestorage/file_types.mm].  This is a [http://freemind.sourceforge.net/wiki/index.php/Main_Page freemind] file: if it is edited the changes will be immediately reflected in Moodle.&lt;br /&gt;
&lt;br /&gt;
As of 2.3 file_types.mm is no longer used, instead the file types are listed in &amp;lt;code&amp;gt;get_mimetypes_array()&amp;lt;/code&amp;gt; in filelib.php (https://github.com/moodle/moodle/blob/master/lib/classes/filetypes.php).&lt;br /&gt;
&lt;br /&gt;
Example usage:  &#039;&#039;&#039;array(&#039;audio&#039;, &#039;video&#039;, &#039;document&#039;)&#039;&#039;&#039;, you can include file extensions as well, for example: &#039;&#039;&#039;array(&#039;.txt&#039;, &#039;.jpg&#039;, &#039;audio&#039;)&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
==== Load existing files into draft area ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
    $entry = new stdClass;&lt;br /&gt;
    $entry-&amp;gt;id = null;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftitemid = file_get_submitted_draft_itemid(&#039;attachments&#039;);&lt;br /&gt;
&lt;br /&gt;
file_prepare_draft_area($draftitemid, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id,&lt;br /&gt;
                        array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
&lt;br /&gt;
$entry-&amp;gt;attachments = $draftitemid;&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Store updated set of files ====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // ... store or update $entry&lt;br /&gt;
    file_save_draft_area_files($data-&amp;gt;attachments, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;attachment&#039;,&lt;br /&gt;
                   $entry-&amp;gt;id, array(&#039;subdirs&#039; =&amp;gt; 0, &#039;maxbytes&#039; =&amp;gt; $maxbytes, &#039;maxfiles&#039; =&amp;gt; 50));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===editor===&lt;br /&gt;
There are two ways of using the editor element in code, the first one is easier but expects some standardized fields. The second method is more low level.&lt;br /&gt;
&lt;br /&gt;
====Simple use====&lt;br /&gt;
# name database fields: &#039;&#039;textfield&#039;&#039;, &#039;&#039;textfieldformat&#039;&#039; (and &#039;&#039;textfieldtrust&#039;&#039; if required)&lt;br /&gt;
# create options array.  note that context is the best, most local context you have available.  &amp;lt;code php&amp;gt;$textfieldoptions = array(&#039;trusttext&#039;=&amp;gt;true, &#039;subdirs&#039;=&amp;gt;true, &#039;maxfiles&#039;=&amp;gt;$maxfiles,&lt;br /&gt;
                          &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;context&#039;=&amp;gt;$context);&amp;lt;/code&amp;gt;&lt;br /&gt;
# add editor &#039;&#039;textfield_editor&#039;&#039; to moodle form, pass options through custom data in form constructor, set $data-&amp;gt;id to null if data not exist yet &amp;lt;code php&amp;gt;$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;textfield_editor&#039;, get_string(&#039;fieldname&#039;, &#039;somemodule&#039;),&lt;br /&gt;
                   null, $textfieldoptions);&amp;lt;/code&amp;gt;&lt;br /&gt;
# prepare data &amp;lt;code php&amp;gt;$data = file_prepare_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context,&lt;br /&gt;
                                     &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
# get submitted data and after inserting/updating of data &amp;lt;code php&amp;gt;$data = file_postupdate_standard_editor($data, &#039;textfield&#039;, $textfieldoptions, $context,&lt;br /&gt;
                                        &#039;mod_somemodule&#039;, &#039;somearea&#039;, $data-&amp;gt;id);&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Real world examples are in mod/glossary/edit.php and mod/glossary/comment.php&lt;br /&gt;
&lt;br /&gt;
====Low level use====&lt;br /&gt;
&lt;br /&gt;
When using editor element you  need to preprocess and postprocess the data:&lt;br /&gt;
# detect if form was already submitted (usually means draft is area already exists) - &#039;&#039;file_get_submitted_draft_itemid()&#039;&#039;&lt;br /&gt;
# prepare draft file area, temporary storage of all files attached to the text - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# convert encoded relative links to absolute links - &#039;&#039;file_prepare_draft_area()&#039;&#039;&lt;br /&gt;
# create form and set current data&lt;br /&gt;
# after submission the changed files must be merged back into original area - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
# absolute links have to be replaced by relative links - &#039;&#039;file_save_draft_area_files()&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=====Replace old htmleditor with editor=====&lt;br /&gt;
&lt;br /&gt;
The file picker has been integrated with with TinyMCE to make the editor element. This new element should support all types on editors and should be able to switch them on-the-fly. Instances of the old htmleditor element in your forms should be replaced by the new editor element, this may need adding of new format and trusttext columns. For example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;entry&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
        array(&#039;maxfiles&#039; =&amp;gt; EDITOR_UNLIMITED_FILES));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
The editor element can take following options: maxfiles, maxbytes, subdirs and changeformat. Please note that the embedded files is optional feature and is not expected be used everywhere.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: the editor element now includes text format option. You should no longer use the separate format element type.&lt;br /&gt;
&lt;br /&gt;
=====Prepare current data - text and files=====&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (empty($entry-&amp;gt;id)) {&lt;br /&gt;
  $entry = new object();&lt;br /&gt;
  $entry-&amp;gt;id = null;&lt;br /&gt;
  $entry-&amp;gt;definition = &#039;&#039;;&lt;br /&gt;
  $entry-&amp;gt;format = FORMAT_HTML;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
$draftid_editor = file_get_submitted_draft_itemid(&#039;entry&#039;);&lt;br /&gt;
$currenttext = file_prepare_draft_area($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                       $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $entry-&amp;gt;definition);&lt;br /&gt;
$entry-&amp;gt;entry = array(&#039;text&#039;=&amp;gt;$currenttext, &#039;format&#039;=&amp;gt;$entry-&amp;gt;format, &#039;itemid&#039;=&amp;gt;$draftid_editor);&lt;br /&gt;
&lt;br /&gt;
$mform-&amp;gt;set_data($entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If there are multiple files, they will share the same itemid.&lt;br /&gt;
&lt;br /&gt;
=====Obtain text, format and save draft files=====&lt;br /&gt;
&lt;br /&gt;
To retrieve editor content, you need to use following code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // content of editor&lt;br /&gt;
    $messagetext = $fromform-&amp;gt;entry[&#039;text&#039;];&lt;br /&gt;
    // format of content&lt;br /&gt;
    $messageformat  = $fromform-&amp;gt;entry[&#039;format&#039;];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When a user selects a file using the file picker, the file is initially stored in a draft file area, and a URL is inserted into the HTML in the editor that lets the person editing the content (but no one else) see the file.&lt;br /&gt;
&lt;br /&gt;
When the user submits the form, we then need to save the draft files to the correct place in permanent storage. (Just like you have to call $DB-&amp;gt;update_record(&#039;tablename&#039;, $data); to have the other parts of the form submission stored correctly.)&lt;br /&gt;
&lt;br /&gt;
The save_files_from_draft_area function and replace absolute links with internal relative links do:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_save_draft_area_files($draftid_editor, $context-&amp;gt;id, &#039;mod_glossary&#039;, &#039;entry&#039;,&lt;br /&gt;
                                          $entry-&amp;gt;id, array(&#039;subdirs&#039;=&amp;gt;true), $messagetext);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $context-&amp;gt;id, &#039;component&#039;, &#039;proper_file_area&#039; and $entry-&amp;gt;id : correspond to the contextid, filearea and itemid columns in the [[File_API#Table:_files|files table]].&lt;br /&gt;
; $messagetext : this is the message text. As the files are saved to the real file area, the URLs in this content are rewritten.&lt;br /&gt;
&lt;br /&gt;
All URLs in content that point to files managed to the File API are converted to a form that starts &#039;@@PLUGINFILE@@/&#039; before the content is stored in the database. That is what we mean by rewriting.&lt;br /&gt;
&lt;br /&gt;
== File serving==&lt;br /&gt;
&lt;br /&gt;
=== Convert internal relative links to absolute links ===&lt;br /&gt;
&lt;br /&gt;
Before text content is displayed to the user, any URLs in the &#039;@@PLUGINFILE@@/&#039; form in the content need to be rewritten to the real URL where the user can access the files. &lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messagetext = file_rewrite_pluginfile_urls($messagetext, &#039;pluginfile.php&#039;,&lt;br /&gt;
        $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
; $messagetext : is the content containing the @@PLUGINFILE@@ URLs from the database.&lt;br /&gt;
; &#039;pluginfile.php&#039; : there are a number of different scripts that can serve files with different permissions checks. You need to specify which one to use.&lt;br /&gt;
; $context-&amp;gt;id, &#039;mod_mymodule&#039;, &#039;proper_file_area&#039;, $itemid : uniquely identifies the file area, as before.&lt;br /&gt;
&lt;br /&gt;
=== Implement file serving access control ===&lt;br /&gt;
&lt;br /&gt;
Attachments and embedded images should have the same access control like the text itself, in majority of cases these files are served using pluginfile.php. Access control is defined in &#039;&#039;module/lib.php&#039;&#039; file in function &#039;&#039;module_pluginfile()&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== File browsing support ==&lt;br /&gt;
Only owner of each file area is allowed to use low level File API function to access files, other parts of Moodle should use file browsing API.&lt;br /&gt;
&lt;br /&gt;
Activities may specify browsing support in own module/lib.php file by implementing functions module_get_file_areas() and module_get_file_info().&lt;br /&gt;
&lt;br /&gt;
== Upgrading your code ==&lt;br /&gt;
Here I will attempt to describe some simple steps you can take to upgrade your file-handling form elements from pre-2.0 code to 2.0. We will use the example of glossary, since it has been used above.&lt;br /&gt;
&lt;br /&gt;
=== Preparing your options ===&lt;br /&gt;
Unless you are happy with the defaults, you will need to define an array of options for each file-handling form element. You could define it at different places, but it&#039;s best to put it in one place and make the array(s) available to other files if they need it. In the majority of cases, this will be in a file like edit.php&lt;br /&gt;
&lt;br /&gt;
Previous code in mod/glossary/edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform =&amp;amp; new mod_glossary_entry_form(null, compact(&#039;cm&#039;, &#039;glossary&#039;, &#039;hook&#039;, &#039;mode&#039;, &#039;e&#039;, &#039;context&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$maxbytes = $course-&amp;gt;maxbytes;&lt;br /&gt;
// Could also use $CFG-&amp;gt;maxbytes if you are not coding within a course context&lt;br /&gt;
&lt;br /&gt;
$definitionoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes, &#039;trusttext&#039;=&amp;gt;true,&lt;br /&gt;
                           &#039;context&#039;=&amp;gt;$context);&lt;br /&gt;
$attachmentoptions = array(&#039;subdirs&#039;=&amp;gt;false, &#039;maxfiles&#039;=&amp;gt;99, &#039;maxbytes&#039;=&amp;gt;$maxbytes);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that the data being passed to the form constructor have changed also, but this is not part of the file API changes, I just include them to avoid confusion.&lt;br /&gt;
&lt;br /&gt;
These options are for the htmleditor (definition field) and the filemanager (attachment field). They are used by a file called edit_form.php.&lt;br /&gt;
&lt;br /&gt;
=== Element preparation ===&lt;br /&gt;
Before we look at this, however, we need to &amp;quot;prepare&amp;quot; the elements so that they can correctly display existing embedded images and attached files when you are editing a record instead of just creating one. So, let&#039;s take the code we&#039;ve got so far in edit.php and add to it:&lt;br /&gt;
&lt;br /&gt;
Currently upgraded code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&lt;br /&gt;
        &#039;current&#039;=&amp;gt;$entry, &lt;br /&gt;
        &#039;cm&#039;=&amp;gt;$cm, &lt;br /&gt;
        &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
        &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
        &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code with element preparation:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$entry = file_prepare_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                      &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_prepare_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                           &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$mform = new mod_glossary_entry_form(null, array(&#039;current&#039;=&amp;gt;$entry, &#039;cm&#039;=&amp;gt;$cm, &#039;glossary&#039;=&amp;gt;$glossary,&lt;br /&gt;
                                                 &#039;definitionoptions&#039;=&amp;gt;$definitionoptions, &lt;br /&gt;
                                                 &#039;attachmentoptions&#039;=&amp;gt;$attachmentoptions));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* $entry in this case is simply a stdClass object which may either represent a new glossary entry or an existing one.&lt;br /&gt;
* $entry-&amp;gt;id must be the unique identifier for the current object. If we are creating a new entry, it will be null, but in all cases it must be defined.&lt;br /&gt;
* These two functions (file_prepare_standard_editor and file_prepare_standard_filemanager) are shortcuts functions that take care of some of the tedious setting up for you, but they make a couple of assumptions:&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; name the form element as {element}_editor or {element}_filemanager (see next section)&lt;br /&gt;
*# You &#039;&#039;&#039;must&#039;&#039;&#039; have at least the following fields in the database: {element} and {element}summary, as described earlier in this documentation&lt;br /&gt;
&lt;br /&gt;
We can now look at the upgrades needed in the form definition file.&lt;br /&gt;
&lt;br /&gt;
=== Form definition ===&lt;br /&gt;
Previous code in mod/glossary/edit_form.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;htmleditor&#039;, &#039;definition&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;),&lt;br /&gt;
                    array(&#039;rows&#039;=&amp;gt;20));&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition&#039;, null, &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;definition&#039;, array(&#039;writing&#039;, &#039;richtext&#039;), false, &#039;editorhelpbutton&#039;);&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;format&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$this-&amp;gt;set_upload_manager(new upload_manager(&#039;attachment&#039;, true, false, $COURSE, false, 0,&lt;br /&gt;
                                             true, true, false));&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;file&#039;, &#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;forum&#039;));&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment&#039;, array(&#039;attachment&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                      &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$definitionoptions = $this-&amp;gt;_customdata[&#039;definitionoptions&#039;];&lt;br /&gt;
$attachmentoptions = $this-&amp;gt;_customdata[&#039;attachmentoptions&#039;];&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;editor&#039;, &#039;definition_editor&#039;, get_string(&#039;definition&#039;, &#039;glossary&#039;), null,&lt;br /&gt;
                   $definitionoptions);&lt;br /&gt;
$mform-&amp;gt;setType(&#039;definition_editor&#039;, PARAM_RAW);&lt;br /&gt;
$mform-&amp;gt;addRule(&#039;definition_editor&#039;, get_string(&#039;required&#039;), &#039;required&#039;, null, &#039;client&#039;);&lt;br /&gt;
// a bit further...&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;filemanager&#039;, &#039;attachment_filemanager&#039;, get_string(&#039;attachment&#039;, &#039;glossary&#039;),&lt;br /&gt;
                   null, $attachmentoptions);&lt;br /&gt;
$mform-&amp;gt;setHelpButton(&#039;attachment_filemanager&#039;, array(&#039;attachment2&#039;,&lt;br /&gt;
                      get_string(&#039;attachment&#039;, &#039;glossary&#039;), &#039;glossary&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note the following:&lt;br /&gt;
* The format element and the help button are no longer required for the HTML editor element&lt;br /&gt;
* The name of the form element needs to be changed by adding &#039;_editor&#039; or &#039;_manager&#039; to the original name. This is a naming convention that is used by a couple of functions we will look at shortly&lt;br /&gt;
* Make sure $definitionoptions has context parameter, else system context is used and editor will not respect filter settings.&lt;br /&gt;
&lt;br /&gt;
=== Handling submitted data ===&lt;br /&gt;
The final step is to handle the submitted data properly, i.e. retrieve the files and save them to disk, associating them with the record we have just created (a glossary entry in our example). This happens in edit.php:&lt;br /&gt;
&lt;br /&gt;
Previous code in edit.php:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Section that updates an entry:&lt;br /&gt;
$todb-&amp;gt;id = $e;&lt;br /&gt;
$dir = glossary_file_area_name($todb);&lt;br /&gt;
if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
    $todb-&amp;gt;attachment = $newfilename;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// Section that adds an entry:&lt;br /&gt;
if ($todb-&amp;gt;id = insert_record(&amp;quot;glossary_entries&amp;quot;, $todb)) {&lt;br /&gt;
    $e = $todb-&amp;gt;id;&lt;br /&gt;
    $dir = glossary_file_area_name($todb);&lt;br /&gt;
    if ($mform-&amp;gt;save_files($dir) and $newfilename = $mform-&amp;gt;get_new_filename()) {&lt;br /&gt;
        set_field(&amp;quot;glossary_entries&amp;quot;, &amp;quot;attachment&amp;quot;, $newfilename, &amp;quot;id&amp;quot;, $todb-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
New code:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// $todb was renamed to $entry, and the code was refactored &lt;br /&gt;
// so that the file-handling code is only used once for either an add or an update action.&lt;br /&gt;
// If an entry is being added, $DB-&amp;gt;insert() has already been called, so we have a valid $entry-&amp;gt;id&lt;br /&gt;
$entry = file_postupdate_standard_editor($entry, &#039;definition&#039;, $definitionoptions, $context,&lt;br /&gt;
                                         &#039;mod_glossary&#039;, &#039;entry&#039;, $entry-&amp;gt;id);&lt;br /&gt;
$entry = file_postupdate_standard_filemanager($entry, &#039;attachment&#039;, $attachmentoptions, $context,&lt;br /&gt;
                                              &#039;mod_glossary&#039;, &#039;attachment&#039;, $entry-&amp;gt;id);&lt;br /&gt;
// store the updated value values&lt;br /&gt;
$DB-&amp;gt;update_record(&#039;glossary_entries&#039;, $entry);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Things to note:&lt;br /&gt;
* If you are adding a new record, you will still need to call update_record after calling the file_postupdate* functions&lt;br /&gt;
&lt;br /&gt;
=== Gotchas ===&lt;br /&gt;
A few things to keep in mind:&lt;br /&gt;
* Make sure that you instantiate the moodle form before any call to $OUTPUT-&amp;gt;header()&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[File API]]&lt;br /&gt;
* [[Using the file API]]&lt;br /&gt;
* [[Repository plugins]]&lt;br /&gt;
* [[Portfolio API]]&lt;br /&gt;
* MDL-14589 - File API Meta issue&lt;br /&gt;
* [http://moodle.org/mod/forum/discuss.php?d=207748 Adding a text editor to a Moodle form]&lt;br /&gt;
&lt;br /&gt;
[[Category:Files]]&lt;br /&gt;
[[Category:Repositories]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_Components&amp;diff=50964</id>
		<title>Output Components</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_Components&amp;diff=50964"/>
		<updated>2016-10-04T12:34:15Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Basic example - fix typ0 */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{obsolete}}&lt;br /&gt;
See [[ Templates ]] for the recommended way to build pages in Moodle from Moodle 2.9.&lt;br /&gt;
&lt;br /&gt;
{{ Moodle 2.0 }}&lt;br /&gt;
&lt;br /&gt;
This page a list of Output Components for Moodle 2.0. It works closely with the Page API, so you may want to refer to that documentation as well.&lt;br /&gt;
&lt;br /&gt;
== Components ==&lt;br /&gt;
Components in the Output API are classes that represent elements to be output. They do not contain any code for outputting anything, but they contain rich meta-data that is used by the Renderers to generate output. Some of the key aspects of components are outlined here:&lt;br /&gt;
* Components do not have defined constructors with arguments. Passing arguments to the default constructor will not do anything useful.&lt;br /&gt;
* Some components have a constructor which is used exclusively to instantiate object member variables.&lt;br /&gt;
* Components consist mainly of variables with sensible defaults, and a prepare() method which makes use of these variables to setup other defaults prior to rendering.&lt;br /&gt;
* The prepare() method always behaves the same way, regardless of which renderer is used. This ensures consistency of the component&#039;s variables.&lt;br /&gt;
* Additional &amp;quot;shortcut&amp;quot; methods are sometimes added to provide a more high-level API to developers.&lt;br /&gt;
&lt;br /&gt;
=== moodle_html_component ===&lt;br /&gt;
*This is the base class for all output components. It is not declared as abstract, because you could actually use it to instantiate a basic component. However, almost all rendering functions will expect a sub-class of this class as a parameter, so instantiating it is unlikely to be very useful.&lt;br /&gt;
*This class basically holds data and useful functions that can apply to any component, such as id, classes, style, alt and title (HTML attributes valid for any XHTML element). It also handles the collection and setting up of component_actions, which are described below. Refer to the class&#039; PHP docs for details on variables and functions.&lt;br /&gt;
*This class also defines a function for generating unique HTML ids for components that require one, and holds a static array for generated ids to prevent duplication.&lt;br /&gt;
*A set_label($text, $for=null) is defined, with the first argument accepting either a string or a html_label component, in which latter case the second argument is ignored. If the component does not have an $id value, one will be generated and assigned to the label&#039;s $for value unless a html_label object is given as the $text argument. For this reason, if you explicitly set a component&#039;s $id value, make sure set_label() is called after you set that value.&lt;br /&gt;
&lt;br /&gt;
=== HTML low-level components ===&lt;br /&gt;
This list of components replicate basic HTML elements. They are prefixed with html_ to make it clear that they are the basic building blocks of the output API.&lt;br /&gt;
&lt;br /&gt;
==== html_label ====&lt;br /&gt;
*Many HTML elements may have a label (input fields, dropdowns etc.). Some rendering functions look for this label and render it accordingly.&lt;br /&gt;
*html_label requires a $text value, and should be given a $for value for accessibility reasons. It is rendered ultimately by $OUTPUT-&amp;gt;label(html_label $label).&lt;br /&gt;
&lt;br /&gt;
==== html_field ====&lt;br /&gt;
*Represents a HTML input field. Can be used to output any input type, although some of its variables only apply to some types (e.g. maxlength only applies to text inputs).&lt;br /&gt;
*It has a shortcut method for preparing a text input: make_text($name, $value, $alt, $maxlength).&lt;br /&gt;
&lt;br /&gt;
==== html_button ====&lt;br /&gt;
*Represents a HTML button, which may be rendered in many different ways, though by default it is rendered as an input field of type &amp;quot;button&amp;quot;.&lt;br /&gt;
*Requires a $text value (by default used as the HTML &amp;quot;value&amp;quot; attribute)&lt;br /&gt;
&lt;br /&gt;
==== action_link ====&lt;br /&gt;
*Represents a link, by default rendered by the $OUTPUT-&amp;gt;link() function as HTML: &lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;$url&amp;quot;&amp;gt;$text&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== html_image ====&lt;br /&gt;
*Simple class representing an image, rendered by $OUTPUT-&amp;gt;image().&lt;br /&gt;
*The $alt variable is set to HTML_ATTR_EMPTY by default. This constant is interpreted by the renderer as an attribute with an empty string as a value. If you use an actual empty string, the attribute will not be output at all, which would break XHTML strict for the &amp;lt;img/&amp;gt; tag.&lt;br /&gt;
&lt;br /&gt;
==== html_form ====&lt;br /&gt;
*This component represents a form &#039;wrapper&#039; with an optional html_button object. You can use $OUTPUT-&amp;gt;form($form, $contents) to output a form with any HTML you want within it.&lt;br /&gt;
*The object requires a $url value, which can either be a string or a moodle_url object. In the prepare() method, this variable will be converted to a moodle_url.&lt;br /&gt;
*If the $method &amp;quot;post&amp;quot; is used, the sesskey param will be added automatically&lt;br /&gt;
*You can use the $params array to specify hidden inputs, but it will be ignored if you give a moodle_url as the $url value (because moodle_urls include query params).&lt;br /&gt;
*This object is also used by the $OUTPUT-&amp;gt;button($formwithbutton) and the $OUTPUT-&amp;gt;confirm($message, $formcontinue, $formcancel) methods.&lt;br /&gt;
&lt;br /&gt;
==== html_list ====&lt;br /&gt;
*Represents a HTML nested list.&lt;br /&gt;
*Has a load_data($tree, $level=0) recursive method which take a nested array and stores instantiated html_list_item objects in the $items array.&lt;br /&gt;
*CSS classes are automatically added to each element in the list, to allow for custom styling.&lt;br /&gt;
*This is rendered by $OUTPUT-&amp;gt;htmllist($list) as a &amp;lt;nowiki&amp;gt;&amp;lt;ul&amp;gt; or &amp;lt;ol&amp;gt;&amp;lt;/nowiki&amp;gt; element, but could be used to output nav menus etc. by yet unwritten output methods.&lt;br /&gt;
*Use the $type variable to specify if the list should be ordered or unordered.&lt;br /&gt;
&lt;br /&gt;
==== html_list_item ====&lt;br /&gt;
*Represents a list item used by the html_list component. Only has a $value variable, but also benefits from all other variables and methods of the moodle_html_component base class.&lt;br /&gt;
&lt;br /&gt;
==== html_table ====&lt;br /&gt;
*Represents a HTML table with data&lt;br /&gt;
*Is intended to replace the old flexible_table class&lt;br /&gt;
*The $data array either holds an associate array of arrays representing rows and cells, or it can be set up with html_table_row and html_table_cell objects, for finer control over the look and layout of the table cells.&lt;br /&gt;
*In the html_writer::table($table) method, the $data array&#039;s contents are converted into html_table_row and html_table_cell objects if they are not already of that type.&lt;br /&gt;
&lt;br /&gt;
==== html_table_row ====&lt;br /&gt;
*A simple component holding an array of html_table_cell objects.&lt;br /&gt;
&lt;br /&gt;
==== html_table_cell ====&lt;br /&gt;
*This represents a table cell, and is aggregated by a html_table_row object, itself aggregated by html_table.&lt;br /&gt;
*This component&#039;s variables mirror those of the XHTML &amp;lt;nowiki&amp;gt;&amp;lt;td&amp;gt; or &amp;lt;th&amp;gt;&amp;lt;/nowiki&amp;gt; elements (differentiated by the $header boolean)&lt;br /&gt;
&lt;br /&gt;
==== html_select ====&lt;br /&gt;
*This object is by far the most complex HTML component in Moodle. It represents any element that presents the user with a choice. This includes:&lt;br /&gt;
*#A dropdown menu (&amp;lt;nowiki&amp;gt;&amp;lt;select&amp;gt; tag&amp;lt;/nowiki&amp;gt;), optionally with automatic redirection upon selection of an option&lt;br /&gt;
*#A set of radio buttons (&amp;lt;nowiki&amp;gt;&amp;lt;input type=&amp;quot;radio&amp;quot; /&amp;gt; tag&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
*#A set of checkboxes (&amp;lt;nowiki&amp;gt;&amp;lt;input type=&amp;quot;checkbox&amp;quot; /&amp;gt; tag&amp;lt;/nowiki&amp;gt;)&lt;br /&gt;
*However, remember that the HTML tags given above are the default rendering of a html_select object. This object can hold so much data that it could be rendered in a multiple of different ways, not necessarily using these traditional HTML tags.&lt;br /&gt;
*This class has a special method initialise_options() which converts the given $options into html_select_optgroup and html_select_option objects. This allows you to override these options&#039; defaults and add style, classes and component_action objects before the object is sent to the renderer.&lt;br /&gt;
&lt;br /&gt;
*Some examples follow:&lt;br /&gt;
&lt;br /&gt;
===== Basic example =====&lt;br /&gt;
The following will output a basic drop-down menu, ready to be included in a form:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$select = html_select::make(array(&#039;1&#039; =&amp;gt; &#039;Value 1&#039;, &#039;2&#039; =&amp;gt; &#039;Value 2&#039;), &#039;choice1&#039;, &#039;2&#039;);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;select id=&amp;quot;menuchoice1&amp;quot; class=&amp;quot;menuchoice1 select&amp;quot; name=&amp;quot;choice1&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;option value=&amp;quot;0&amp;quot;&amp;gt;Choose...&amp;lt;/option&amp;gt;&lt;br /&gt;
  &amp;lt;option value=&amp;quot;1&amp;quot;&amp;gt;Value 1&amp;lt;/option&amp;gt;&lt;br /&gt;
  &amp;lt;option selected=&amp;quot;selected&amp;quot; value=&amp;quot;2&amp;quot;&amp;gt;Value 2&amp;lt;/option&amp;gt;&lt;br /&gt;
&amp;lt;/select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that a default &amp;quot;Choose...&amp;quot; option with a value of 0 is added to the menu. To remove this, follow the next example:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$select-&amp;gt;nothinglabel = false;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
This will remove the default option completely.&lt;br /&gt;
&lt;br /&gt;
===== Nested menus =====&lt;br /&gt;
You can also render a menu with one level of nesting, rendered as a dropdown with optgroups. You just need to do two things to achieve that:&lt;br /&gt;
#Specify $select-&amp;gt;nested = true&lt;br /&gt;
#Either:&lt;br /&gt;
#*$select-&amp;gt;load_data($flatarray), which requires a rather cryptic syntax with double-dashes for optgroups&lt;br /&gt;
#*$select-&amp;gt;load_data($nestedarray), the first level&#039;s keys are the names of the optgroups, their arrays are the options&#039; value=&amp;gt;label pairs.&lt;br /&gt;
#*Prepare the data directly as html_select_optgroup and html_select_option objects. This method requires more code but less debugging because it is a lot less brittle than a string-based syntax, and it allows more customised classes, JS actions etc. on each individual option.&lt;br /&gt;
&lt;br /&gt;
The preferred method is the second one in the majority of cases, because it is easy to setup and debug. The first method should be avoided and will not be demonstrated here.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Method 2:&lt;br /&gt;
$options = array(&#039;Group1&#039; =&amp;gt; array(&#039;value1&#039; =&amp;gt; &#039;Option 1&#039;, &#039;value2&#039; =&amp;gt; &#039;Option 2&#039;), &#039;Group2&#039; =&amp;gt; array(&#039;value3&#039; =&amp;gt; &#039;Option 3&#039;, &#039;value4&#039; =&amp;gt; &#039;Option 4&#039;));&lt;br /&gt;
$select = html_select::make($options, &#039;choice1&#039;, &#039;value1&#039;);&lt;br /&gt;
$select-&amp;gt;nested = true;&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
&lt;br /&gt;
// Method 3:&lt;br /&gt;
$optgroup1 = new html_select_optgroup();&lt;br /&gt;
$optgroup2 = new html_select_optgroup();&lt;br /&gt;
$optgroup1-&amp;gt;text = &#039;Group1&#039;;&lt;br /&gt;
$optgroup2-&amp;gt;text = &#039;Group2&#039;;&lt;br /&gt;
&lt;br /&gt;
$option1 = new html_select_option();&lt;br /&gt;
$option2 = new html_select_option();&lt;br /&gt;
$option3 = new html_select_option();&lt;br /&gt;
$option4 = new html_select_option();&lt;br /&gt;
&lt;br /&gt;
$option1-&amp;gt;text = &#039;Option 1&#039;;&lt;br /&gt;
$option1-&amp;gt;value = &#039;value1&#039;;&lt;br /&gt;
$option2-&amp;gt;text = &#039;Option 2&#039;;&lt;br /&gt;
$option2-&amp;gt;value = &#039;value2&#039;;&lt;br /&gt;
$option3-&amp;gt;text = &#039;Option 3&#039;;&lt;br /&gt;
$option3-&amp;gt;value = &#039;value3&#039;;&lt;br /&gt;
$option4-&amp;gt;text = &#039;Option 4&#039;;&lt;br /&gt;
$option4-&amp;gt;value = &#039;value4&#039;;&lt;br /&gt;
&lt;br /&gt;
$optgroup1-&amp;gt;options = array($option1, $option2);&lt;br /&gt;
$optgroup2-&amp;gt;options = array($option3, $option4);&lt;br /&gt;
&lt;br /&gt;
$select = html_select::make(array($optgroup1, $optgroup2), &#039;choice1&#039;, &#039;value1&#039;);&lt;br /&gt;
$select-&amp;gt;nested = true;&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Both these methods Output:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;select id=&amp;quot;menuchoice1&amp;quot; class=&amp;quot;menuchoice1 select&amp;quot; name=&amp;quot;choice1&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;optgroup label=&amp;quot;Group1&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;option selected=&amp;quot;selected&amp;quot; value=&amp;quot;value1&amp;quot;&amp;gt;Option 1&amp;lt;/option&amp;gt;&lt;br /&gt;
    &amp;lt;option value=&amp;quot;value2&amp;quot;&amp;gt;Option 2&amp;lt;/option&amp;gt;&lt;br /&gt;
  &amp;lt;/optgroup&amp;gt;&lt;br /&gt;
  &amp;lt;optgroup label=&amp;quot;Group2&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;option value=&amp;quot;value3&amp;quot;&amp;gt;Option 3&amp;lt;/option&amp;gt;&lt;br /&gt;
    &amp;lt;option value=&amp;quot;value4&amp;quot;&amp;gt;Option 4&amp;lt;/option&amp;gt;&lt;br /&gt;
  &amp;lt;/optgroup&amp;gt;&lt;br /&gt;
&amp;lt;/select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Although the last method looks very code-intensive, most of it would obviously be reduced using foreach loops, and it allows for much more customisation of the components.&lt;br /&gt;
&lt;br /&gt;
===== Yes/No menu =====&lt;br /&gt;
A common use case is to print a Yes/No menu. This could be output as two radio buttons, but it is sometimes output as a menu. The two cases are demonstrated here:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$select = html_select::make_yes_no(&#039;choice1&#039;, 1);&lt;br /&gt;
$select-&amp;gt;nothinglabel = false; // Don&#039;t forget to do this, or the &amp;quot;Choose...&amp;quot; option will appear and have the same value as the &amp;quot;No&amp;quot; option!&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;select id=&amp;quot;menuchoice1&amp;quot; class=&amp;quot;menuchoice1 select&amp;quot; name=&amp;quot;choice1&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;option value=&amp;quot;0&amp;quot;&amp;gt;No&amp;lt;/option&amp;gt;&lt;br /&gt;
  &amp;lt;option selected=&amp;quot;selected&amp;quot; value=&amp;quot;1&amp;quot;&amp;gt;Yes&amp;lt;/option&amp;gt;&lt;br /&gt;
&amp;lt;/select&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Radio buttons:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$select-&amp;gt;rendertype = &#039;radio&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;span class=&amp;quot;radiogroup choice1 rb0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;label for=&amp;quot;html_select_option-b4d4bd&amp;quot;&amp;gt;No&amp;lt;/label&amp;gt;&lt;br /&gt;
  &amp;lt;input id=&amp;quot;html_select_option-b4d4bd&amp;quot; type=&amp;quot;radio&amp;quot; name=&amp;quot;choice1&amp;quot; value=&amp;quot;0&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;radiogroup choice1 rb1&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;label for=&amp;quot;html_select_option-1eaa39&amp;quot;&amp;gt;Yes&amp;lt;/label&amp;gt;&lt;br /&gt;
  &amp;lt;input id=&amp;quot;html_select_option-1eaa39&amp;quot; type=&amp;quot;radio&amp;quot; checked=&amp;quot;checked&amp;quot; name=&amp;quot;choice1&amp;quot; value=&amp;quot;1&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
However, in many cases it is better to display a yes/no choice as a single checkbox. For this purpose, it is better to instantiate a single html_option object and pass it to $OUTPUT-&amp;gt;checkbox().&lt;br /&gt;
&lt;br /&gt;
===== Date/Time selectors =====&lt;br /&gt;
NOTE: This part of the API is under review&lt;br /&gt;
&lt;br /&gt;
The html_select object can be used to output date or time selectors. A shortcut method is provided for this purpose: make_time_selector($type, $currenttime, $step);&lt;br /&gt;
For more concise code, you can use the higher-level method make_time_selectors($selectors, $currentime, $step);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$dayselector = html_select::make_time_selector(&#039;days&#039;, &#039;myday&#039;, &#039;120308000&#039;);&lt;br /&gt;
$monthselector = html_select::make_time_selector(&#039;months&#039;, &#039;mymonth&#039;, &#039;120308000&#039;);&lt;br /&gt;
$yearselector = html_select::make_time_selector(&#039;years&#039;, &#039;myyear&#039;, &#039;120308000&#039;);&lt;br /&gt;
$hourselector = html_select::make_time_selector(&#039;hours&#039;, &#039;myhour&#039;, &#039;120308000&#039;);&lt;br /&gt;
$minuteselector = html_select::make_time_selector(&#039;minutes&#039;, &#039;myminute&#039;, &#039;120308000&#039;, 5);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($dayselector);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($monthselector);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($yearselector);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($hourselector);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($minuteselector);&lt;br /&gt;
&lt;br /&gt;
// OR&lt;br /&gt;
$selectors = html_select::make_time_selectors(array(&#039;days&#039; =&amp;gt; &#039;myday&#039;, &#039;months&#039; =&amp;gt; &#039;mymonth&#039;, &#039;years&#039; =&amp;gt; &#039;myyear&#039;, &#039;hours&#039; =&amp;gt; &#039;myhour&#039;, &#039;minutes&#039; =&amp;gt; &#039;myminute&#039;), &#039;120308000&#039;, 5);&lt;br /&gt;
foreach ($selectors as $select) {&lt;br /&gt;
    echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
[[Image:timeselectors.png]]&lt;br /&gt;
&lt;br /&gt;
===== Popup Forms =====&lt;br /&gt;
*This is a really bad name for a dropdown menu that redirects the user when an option is selected.&lt;br /&gt;
*html_select::make_popup_form() is a shortcut method for returning an object ready for rendering through $OUTPUT-&amp;gt;select()&lt;br /&gt;
*The basic premise of a &amp;quot;popup form&amp;quot; is that each option has as its value the URL to which the user should be redirected when that option is selected&lt;br /&gt;
*To simplify this process, make_popup_form() takes a URL as its first argument, and the name of a query param as the second. It is expected that the option values represent the value that will be assigned to this &amp;quot;variable&amp;quot; parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options = array(1 =&amp;gt; &#039;Page 1&#039;, 2 =&amp;gt; &#039;Page 2&#039;, 3 =&amp;gt; &#039;Page 3&#039;);&lt;br /&gt;
$select = html_select::make_popup_form(&#039;http://domain.com/index.php&#039;, &#039;id&#039;, $options, &#039;myform&#039;);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;form id=&amp;quot;myform&amp;quot; class=&amp;quot;popupform&amp;quot; action=&amp;quot;http://enterprise/cvs_moodle_head/course/jumpto.php&amp;quot; method=&amp;quot;get&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;JEgniUhzzx&amp;quot; name=&amp;quot;sesskey&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;select id=&amp;quot;myform_jump&amp;quot; class=&amp;quot;menujump select&amp;quot; name=&amp;quot;jump&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;0&amp;quot;&amp;gt;Choose...&amp;lt;/option&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;http://domain.com/index.php?id=1&amp;quot;&amp;gt;Page 1&amp;lt;/option&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;http://domain.com/index.php?id=2&amp;quot;&amp;gt;Page 2&amp;lt;/option&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;http://domain.com/index.php?id=3&amp;quot;&amp;gt;Page 3&amp;lt;/option&amp;gt;&lt;br /&gt;
    &amp;lt;/select&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;noscriptmyform&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;input class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Go&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Sometimes you will need some of the URLs to have a different base, or to have more parameters that change between options. The best way to achieve this is demonstrated here:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$options = array(&#039;http://domain.com/index.php?id=1&#039; =&amp;gt; &#039;Page 1&#039;, &lt;br /&gt;
                 &#039;http://domain.com/otherpage/index.php?modid=1&#039; =&amp;gt; &#039;Page 2&#039;, &lt;br /&gt;
                 &#039;http://domain.com/index.php?id=1&amp;amp;othervar=2&#039; =&amp;gt; &#039;Page 3&#039;);&lt;br /&gt;
$select = html_select::make_popup_form(&#039;&#039;, &#039;&#039;, $options, &#039;myform&#039;);&lt;br /&gt;
$select-&amp;gt;override_option_values($options);&lt;br /&gt;
echo $OUTPUT-&amp;gt;select($select);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;form id=&amp;quot;myform&amp;quot; class=&amp;quot;popupform&amp;quot; action=&amp;quot;http://enterprise/cvs_moodle_head/course/jumpto.php&amp;quot; method=&amp;quot;get&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;JEgniUhzzx&amp;quot; name=&amp;quot;sesskey&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;select id=&amp;quot;myform_jump&amp;quot; class=&amp;quot;menujump select&amp;quot; name=&amp;quot;jump&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;0&amp;quot;&amp;gt;Choose...&amp;lt;/option&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;http://domain.com/index.php?id=1&amp;quot;&amp;gt;Page 1&amp;lt;/option&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;http://domain.com/otherpage/index.php?modid=1&amp;quot;&amp;gt;Page 2&amp;lt;/option&amp;gt;&lt;br /&gt;
      &amp;lt;option value=&amp;quot;http://domain.com/index.php?id=1&amp;amp;othervar=2&amp;quot;&amp;gt;Page 3&amp;lt;/option&amp;gt;&lt;br /&gt;
    &amp;lt;/select&amp;gt;&lt;br /&gt;
    &amp;lt;div id=&amp;quot;noscriptmyform&amp;quot; style=&amp;quot;display: none;&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;input class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Go&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== html_select_option ====&lt;br /&gt;
*This component represents an option&lt;br /&gt;
*It is not necessarily rendered as an &amp;lt;nowiki&amp;gt;&amp;lt;option&amp;gt;&amp;lt;/nowiki&amp;gt; tag, but can also be rendered as a radio or a checkbox&lt;br /&gt;
*It can be aggregated by html_select and html_select_optgroup, or used by itself in $OUTPUT-&amp;gt;checkbox($option, $name)&lt;br /&gt;
*It has a shortcut method for preparing a checkbox for output: make_checkbox($value, $selected, $label, $alt);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$checkbox = html_select_option::make_checkbox(&#039;1&#039;, false, get_string(&#039;donotask&#039;));&lt;br /&gt;
echo $OUTPUT-&amp;gt;checkbox($checkbox, &#039;donotask&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;checkbox donotask&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;input id=&amp;quot;html_select_option-e7be90&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;donotask&amp;quot; value=&amp;quot;1&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;label for=&amp;quot;html_select_option-e7be90&amp;quot;&amp;gt;Do Not Ask&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
*Note that an ID is generated in this case even though no component_action was added. This is the default behaviour for the checkbox() method.&lt;br /&gt;
&lt;br /&gt;
==== html_select_optgroup ====&lt;br /&gt;
*This represents an option group, used only by html_select to group options together. It doesn&#039;t do anything particularly useful in itself apart from aggregating html_select_option objects and having a text value.&lt;br /&gt;
*It benefits from all the moodle_html_component variables and methods.&lt;br /&gt;
&lt;br /&gt;
=== Moodle components ===&lt;br /&gt;
The following components do not map exactly to HTML elements, so they are prefixed with moodle_.&lt;br /&gt;
&lt;br /&gt;
==== moodle_paging_bar ====&lt;br /&gt;
*Represents a paging bar used to navigate a large list of records like users, forum posts etc.&lt;br /&gt;
*Since 4 parameters are required, a shortcut function is provided: moodle_paging_bar::make($totalcount, $page, $perpage, $baseurl)&lt;br /&gt;
*The first page has a value of 0 but is displayed as 1, so remember this offset.&lt;br /&gt;
*If you have multiple paging bars on one page for different lists, set the $pagevar variable&lt;br /&gt;
*See [[Output_API#paging_bar]] for example usage and output&lt;br /&gt;
&lt;br /&gt;
==== moodle_user_picture ====&lt;br /&gt;
*Represents a user&#039;s picture to be output through $OUTPUT-&amp;gt;user_picture()&lt;br /&gt;
*Requires at least a $user object of stdClass with a minimum of data (id) and a $courseid&lt;br /&gt;
*If no specific image is given (as a html_image object), then the default image is loaded&lt;br /&gt;
*See [[Output_API#user_picture]] for example usage and output&lt;br /&gt;
&lt;br /&gt;
==== moodle_action_icon ====&lt;br /&gt;
*Simply put, this is a linked image.&lt;br /&gt;
*See [[Output_API#action_icon]] for example usage and output&lt;br /&gt;
&lt;br /&gt;
==== moodle_help_icon ====&lt;br /&gt;
See [[Output_API#help_icon]] For example usage. Replaces the old helpbutton() global function.&lt;br /&gt;
&lt;br /&gt;
== Renderers ==&lt;br /&gt;
=== renderer_base ===&lt;br /&gt;
* Simple base class for Moodle renderers.&lt;br /&gt;
* Tracks the xhtml_container_stack to use, which is passed in in the constructor.&lt;br /&gt;
* Also has methods to facilitate generating HTML output.&lt;br /&gt;
&lt;br /&gt;
==== output_tag methods ====&lt;br /&gt;
* Low-level functions for outputting specific HTML tags. &lt;br /&gt;
* For empty tags (with no content), use output_empty_tag&lt;br /&gt;
&lt;br /&gt;
==== pix_url ====&lt;br /&gt;
* Same as old_icon_url, but for old module icons&lt;br /&gt;
* The equivalent for &amp;quot;$CFG-&amp;gt;modpixpath/$mod/icon.gif&amp;quot; is mod_icon_url(&#039;icon&#039;, $mod)&lt;br /&gt;
&lt;br /&gt;
==== prepare_event_handlers(&amp;amp;$component) ====&lt;br /&gt;
* Used by rendering functions to prepare JS event listeners for components that may require it. &lt;br /&gt;
* All components that can receive user input should go through this method&lt;br /&gt;
&lt;br /&gt;
==== prepare_legacy_width_and_height($component) ====&lt;br /&gt;
* Returns the correct CSS for components that have the deprecated $height and/or $width attributes&lt;br /&gt;
&lt;br /&gt;
=== core_renderer ===&lt;br /&gt;
Since these functions are very well documented inline (phpdoc), I will only put examples here, without in-depth explanations.&lt;br /&gt;
&lt;br /&gt;
==== action_icon ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$icon = new moodle_action_icon();&lt;br /&gt;
$icon-&amp;gt;image-&amp;gt;src = $OUTPUT-&amp;gt;old_icon_url(&#039;moodlelogo&#039;);&lt;br /&gt;
$icon-&amp;gt;image-&amp;gt;alt = &#039;What is moodle?&#039;;&lt;br /&gt;
$icon-&amp;gt;link-&amp;gt;url = new moodle_url(&#039;http://domain.com/index.php&#039;);&lt;br /&gt;
$icon-&amp;gt;add_confirm_action(&#039;Are you sure?&#039;); // Optional. Equivalent to doing $icon-&amp;gt;link-&amp;gt;add_confirm_action(&#039;Are you sure?&#039;);&lt;br /&gt;
echo $OUTPUT-&amp;gt;action_icon($icon);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;a id=&amp;quot;html_link-2b4310&amp;quot; href=&amp;quot;http://domain.com/index.php&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;img class=&amp;quot;action-icon image&amp;quot; alt=&amp;quot;What is moodle?&amp;quot; src=&amp;quot;http://enterprise/cvs_moodle_head/pix/moodlelogo.gif&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/a&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
//&amp;lt;![CDATA[ &lt;br /&gt;
YAHOO.util.Event.addListener(&#039;html_link-2b4310&#039;, &#039;click&#039;, confirm_dialog, {&amp;quot;message&amp;quot;:&amp;quot;Are you sure?&amp;quot;});&lt;br /&gt;
//]]&amp;gt; &lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== box, box_start and box_end ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;box(&#039;A message of some kind&#039;);&lt;br /&gt;
// OR&lt;br /&gt;
echo $OUTPUT-&amp;gt;box_start();&lt;br /&gt;
echo &#039;A message of some kind&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;box_end();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;box generalbox&amp;quot;&amp;gt;A message of some kind&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== button ====&lt;br /&gt;
*Be aware that this method&#039;s signature requires a html_form component as its only argument. This form object must have a $button value (html_button)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$form = new html_form();&lt;br /&gt;
$form-&amp;gt;url = new moodle_url(&#039;http://domain.com/index.php&#039;, array(&#039;id&#039; =&amp;gt; 3, &#039;userid&#039; =&amp;gt; 5));&lt;br /&gt;
$form-&amp;gt;button-&amp;gt;text = &#039;My account&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;button($form);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;singlebutton&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;form action=&amp;quot;http://domain.com/index.php&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div&amp;gt;&lt;br /&gt;
      &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;fXlccUgFTz&amp;quot; name=&amp;quot;sesskey&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;3&amp;quot; name=&amp;quot;id&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;5&amp;quot; name=&amp;quot;userid&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;input class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;My account&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== checkbox ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$checkbox = html_select_option::make_checkbox(&#039;1&#039;, false, get_string(&#039;donotask&#039;));&lt;br /&gt;
echo $OUTPUT-&amp;gt;checkbox($checkbox, &#039;donotask&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;checkbox donotask&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;input id=&amp;quot;html_select_option-e7be90&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;donotask&amp;quot; value=&amp;quot;1&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;label for=&amp;quot;html_select_option-e7be90&amp;quot;&amp;gt;Do Not Ask&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== close_window_button ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;close_window_button();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;closewindow&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&amp;quot;singlebutton&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;form action=&amp;quot;http://enterprise/cvs_moodle_head/#&amp;quot; method=&amp;quot;get&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;div&amp;gt;&lt;br /&gt;
        &amp;lt;input id=&amp;quot;html_button-d35ffa&amp;quot; class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Close this window&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/form&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
//&amp;lt;![CDATA[ &lt;br /&gt;
YAHOO.util.Event.addListener(&#039;html_button-d35ffa&#039;, &#039;click&#039;, close_window);&lt;br /&gt;
//]]&amp;gt; &lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== confirm ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;confirm(&#039;Are you sure?&#039;, &#039;/index.php?delete=1&#039;, &#039;/index.php&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;notice&amp;quot; class=&amp;quot;box generalbox&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;p&amp;gt;Are you sure?&amp;lt;/p&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&amp;quot;buttons&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;singlebutton&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;form action=&amp;quot;http://enterprise/cvs_moodle_head/index.php&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div&amp;gt;&lt;br /&gt;
          &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;fXlccUgFTz&amp;quot; name=&amp;quot;sesskey&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;1&amp;quot; name=&amp;quot;delete&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;input class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Yes&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;/form&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;div class=&amp;quot;singlebutton&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;form action=&amp;quot;http://enterprise/cvs_moodle_head/index.php&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;&lt;br /&gt;
        &amp;lt;div&amp;gt;&lt;br /&gt;
          &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;fXlccUgFTz&amp;quot; name=&amp;quot;sesskey&amp;quot;/&amp;gt;&lt;br /&gt;
          &amp;lt;input class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;No&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;/div&amp;gt;&lt;br /&gt;
      &amp;lt;/form&amp;gt;&lt;br /&gt;
    &amp;lt;/div&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== container, container_start and container_end ====&lt;br /&gt;
*Container differs from box in two ways:&lt;br /&gt;
*#It doesn&#039;t add default CSS classes (box adds a &amp;quot;box&amp;quot; class and a &amp;quot;generalbox&amp;quot; class unless the default is overridden)&lt;br /&gt;
*#It is stored in the XHTML stack as a &amp;quot;container&amp;quot;, not a &amp;quot;box&amp;quot;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;container(&#039;A message of some kind&#039;, &#039;important&#039;, &#039;notice&#039;);&lt;br /&gt;
// OR&lt;br /&gt;
echo $OUTPUT-&amp;gt;container_start(&#039;important&#039;, &#039;notice&#039;);&lt;br /&gt;
echo &#039;A message of some kind&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;container_end();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div id=&amp;quot;notice&amp;quot; class=&amp;quot;important&amp;quot;&amp;gt;A message of some kind&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== continue_button ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;continue_button(&#039;http://domain.com/index.php?id=2&amp;amp;userid=4&#039;);&lt;br /&gt;
// OR (preferred)&lt;br /&gt;
echo $OUTPUT-&amp;gt;continue_button(new moodle_url(&#039;http://domain.com/index.php&#039;, array(&#039;id&#039; =&amp;gt; 2, &#039;userid&#039; =&amp;gt; 4)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;continuebutton&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div class=&amp;quot;singlebutton&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;form action=&amp;quot;http://domain.com/index.php&amp;quot; method=&amp;quot;get&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;div&amp;gt;&lt;br /&gt;
        &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;2&amp;quot; name=&amp;quot;id&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;4&amp;quot; name=&amp;quot;userid&amp;quot;/&amp;gt;&lt;br /&gt;
        &amp;lt;input class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Continue&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;/form&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== doc_link ====&lt;br /&gt;
Not for general use.&lt;br /&gt;
&lt;br /&gt;
==== error_text ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;error_text(&amp;quot;It&#039;s all broken!&amp;quot;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;error&amp;quot;&amp;gt;It&#039;s all broken!&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== footer ====&lt;br /&gt;
*Simply call $OUTPUT-&amp;gt;footer() at the end of each page. &lt;br /&gt;
*The output may vary depending on which page you are on.&lt;br /&gt;
&lt;br /&gt;
==== form ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$form = new html_form();&lt;br /&gt;
$form-&amp;gt;url = new moodle_url(&#039;http://domain.com/index.php&#039;, array(&#039;id&#039; =&amp;gt; 3, &#039;userid&#039; =&amp;gt; 5));&lt;br /&gt;
$checkbox = html_select_option::make_checkbox(1, false, &#039;Agree to terms&#039;);&lt;br /&gt;
$contents = $OUTPUT-&amp;gt;container(&#039;Terms and conditions: Be kind and courteous&#039;);&lt;br /&gt;
$contents .= $OUTPUT-&amp;gt;checkbox($checkbox, &#039;agree&#039;);&lt;br /&gt;
echo $OUTPUT-&amp;gt;form($form, $contents);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;form action=&amp;quot;http://domain.com/index.php&amp;quot; method=&amp;quot;post&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;div&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;79D3tSzYfz&amp;quot; name=&amp;quot;sesskey&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;3&amp;quot; name=&amp;quot;id&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;input type=&amp;quot;hidden&amp;quot; value=&amp;quot;5&amp;quot; name=&amp;quot;userid&amp;quot;/&amp;gt;&lt;br /&gt;
    &amp;lt;div&amp;gt;Terms and conditions: Be kind and courteous&amp;lt;/div&amp;gt;&lt;br /&gt;
    &amp;lt;span class=&amp;quot;checkbox agree&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;input id=&amp;quot;html_select_option-3a3de0&amp;quot; type=&amp;quot;checkbox&amp;quot; name=&amp;quot;agree&amp;quot; value=&amp;quot;1&amp;quot;/&amp;gt;&lt;br /&gt;
      &amp;lt;label for=&amp;quot;html_select_option-3a3de0&amp;quot;&amp;gt;Agree to terms&amp;lt;/label&amp;gt;&lt;br /&gt;
    &amp;lt;/span&amp;gt;&lt;br /&gt;
    &amp;lt;input class=&amp;quot;singlebutton&amp;quot; type=&amp;quot;submit&amp;quot; value=&amp;quot;Submit&amp;quot;/&amp;gt;&lt;br /&gt;
  &amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/form&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== header ====&lt;br /&gt;
==== heading ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;heading(get_string(&#039;help&#039;), 3, &#039;helptitle&#039;, &#039;uniqueid&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;h3 id=&amp;quot;uniqueid&amp;quot; class=&amp;quot;helptitle&amp;quot;&amp;gt;Help&amp;lt;/h3&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== heading_with_help ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$helpicon = new moodle_help_icon();&lt;br /&gt;
$helpicon-&amp;gt;page = &#039;posts&#039;;&lt;br /&gt;
$helpicon-&amp;gt;text = &#039;Help about forum posts&#039;;&lt;br /&gt;
$helpicon-&amp;gt;module = &#039;forum&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;heading_with_help($helpicon);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;heading-with-help&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;h2 class=&amp;quot;main help&amp;quot;&amp;gt;Help about forum posts&amp;lt;/h2&amp;gt;&lt;br /&gt;
  &amp;lt;span class=&amp;quot;helplink&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;a id=&amp;quot;html_link-7b0b0d&amp;quot; href=&amp;quot;http://enterprise/cvs_moodle_head/help.php?module=forum&amp;amp;amp;file=posts.html&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;img class=&amp;quot;iconhelp image&amp;quot; src=&amp;quot;http://enterprise/cvs_moodle_head/pix/help.gif&amp;quot; alt=&amp;quot;&amp;quot; /&amp;gt;&lt;br /&gt;
    &amp;lt;/a&amp;gt;&lt;br /&gt;
  &amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== help_icon ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$helpicon = new moodle_help_icon();&lt;br /&gt;
$helpicon-&amp;gt;page = &#039;posts&#039;;&lt;br /&gt;
$helpicon-&amp;gt;text = &#039;Help about forum posts&#039;;&lt;br /&gt;
$helpicon-&amp;gt;module = &#039;forum&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;help_icon($helpicon);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;helplink&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;a id=&amp;quot;html_link-42560f&amp;quot; href=&amp;quot;http://enterprise/cvs_moodle_head/help.php?module=forum&amp;amp;amp;file=posts.html&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;img class=&amp;quot;iconhelp image&amp;quot; src=&amp;quot;http://enterprise/cvs_moodle_head/pix/help.gif&amp;quot; alt=&amp;quot;Help about forum posts&amp;quot; title=&amp;quot;Help about forum posts&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== htmllist ====&lt;br /&gt;
Warning - The html_list class and the $OUTPUT-&amp;gt;htmllist methods do not exist!&lt;br /&gt;
Unlike other things on this page the below example will not work.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$data = array(&#039;Group 1&#039; =&amp;gt; array(&#039;Group 1.1&#039; =&amp;gt; array(&#039;Item 1.1.1&#039;, &#039;Item 1.1.2&#039;), &#039;Item 1.2&#039;),&lt;br /&gt;
              &#039;Group 2&#039; =&amp;gt; array(&#039;Item 2.1&#039;, &#039;Item 2.2&#039;, &#039;Item 2.3&#039;));&lt;br /&gt;
$list = new html_list();&lt;br /&gt;
$list-&amp;gt;type = &#039;ordered&#039;;&lt;br /&gt;
$list-&amp;gt;load_data($data);&lt;br /&gt;
echo $OUTPUT-&amp;gt;htmllist($list);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;ol class=&amp;quot;list-0&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Group 1&lt;br /&gt;
    &amp;lt;ol class=&amp;quot;list-1&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;li&amp;gt;Group 1.1&lt;br /&gt;
        &amp;lt;ol class=&amp;quot;list-2&amp;quot;&amp;gt;&lt;br /&gt;
          &amp;lt;li class=&amp;quot;list-item-2-1&amp;quot;&amp;gt;Item 1.1.1&amp;lt;/li&amp;gt;&lt;br /&gt;
          &amp;lt;li class=&amp;quot;list-item-2-2&amp;quot;&amp;gt;Item 1.1.2&amp;lt;/li&amp;gt;&lt;br /&gt;
        &amp;lt;/ol&amp;gt;&lt;br /&gt;
      &amp;lt;/li&amp;gt;&lt;br /&gt;
      &amp;lt;li class=&amp;quot;list-item-1-2&amp;quot;&amp;gt;Item 1.2&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;/ol&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
  &amp;lt;li&amp;gt;Group 2&lt;br /&gt;
    &amp;lt;ol class=&amp;quot;list-1&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;li class=&amp;quot;list-item-1-1&amp;quot;&amp;gt;Item 2.1&amp;lt;/li&amp;gt;&lt;br /&gt;
      &amp;lt;li class=&amp;quot;list-item-1-2&amp;quot;&amp;gt;Item 2.2&amp;lt;/li&amp;gt;&lt;br /&gt;
      &amp;lt;li class=&amp;quot;list-item-1-3&amp;quot;&amp;gt;Item 2.3&amp;lt;/li&amp;gt;&lt;br /&gt;
    &amp;lt;/ol&amp;gt;&lt;br /&gt;
  &amp;lt;/li&amp;gt;&lt;br /&gt;
&amp;lt;/ol&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Notes: &lt;br /&gt;
*The class names are generated automatically. For ol and ul classes, the digit represents the depth of nesting. &lt;br /&gt;
*This is also the meaning of the first digit in the list item classes, the second being the number of the list item in the item&#039;s list.&lt;br /&gt;
*Once you have called $list-&amp;gt;load_data($array), the list-&amp;gt;items array is filled with html_list and html_list_item components, which you can setup in more details in preparation for output.&lt;br /&gt;
&lt;br /&gt;
==== image ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$image = new html_image();&lt;br /&gt;
$image-&amp;gt;src = &#039;http://domain.com/help.gif&#039;;&lt;br /&gt;
$image-&amp;gt;alt = &#039;Helpful icon&#039;;&lt;br /&gt;
$image-&amp;gt;width = 24;&lt;br /&gt;
$image-&amp;gt;height = 24;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;img class=&amp;quot;image&amp;quot; style=&amp;quot;height: 24px; width: 24px;&amp;quot; alt=&amp;quot;Helpful icon&amp;quot; src=&amp;quot;http://domain.com/help.gif&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== label ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$label = new html_label();&lt;br /&gt;
$label-&amp;gt;text = &#039;Form element&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;label($label);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;label&amp;gt;Form element&amp;lt;/label&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is a rather low-level function, you will rarely need to call it directly. Instead, use labels on subclasses of labelled_html_component:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$field = new html_field();&lt;br /&gt;
$field-&amp;gt;name = &#039;variable1&#039;;&lt;br /&gt;
$field-&amp;gt;id = &#039;myfield&#039;;&lt;br /&gt;
$field-&amp;gt;set_label(&#039;Form element&#039;);&lt;br /&gt;
echo $OUTPUT-&amp;gt;textfield($field);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;span class=&amp;quot;textfield variable1&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;label for=&amp;quot;myfield&amp;quot;&amp;gt;Form element&amp;lt;/label&amp;gt;&lt;br /&gt;
  &amp;lt;input id=&amp;quot;myfield&amp;quot; type=&amp;quot;text&amp;quot; style=&amp;quot;width: 4em;&amp;quot; name=&amp;quot;variable1&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/span&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== link ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$link = new action_link();&lt;br /&gt;
$link-&amp;gt;url = new moodle_url(&#039;http://domain.com/index.php&#039;, array(&#039;id&#039; =&amp;gt; 2, &#039;action&#039; =&amp;gt; &#039;browse&#039;)); // required, but you can use a string instead&lt;br /&gt;
$link-&amp;gt;text = &#039;Browse page 2&#039;; // Required&lt;br /&gt;
echo $OUTPUT-&amp;gt;link($link)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;a href=&amp;quot;http://domain.com/index.php?id=2&amp;amp;amp;action=browse&amp;quot;&amp;gt;Browse page 2&amp;lt;/a&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== link_to_popup ====&lt;br /&gt;
*Same API as for link(), but you set a popup_action on the component, and link() will forward it to the link_to_popup() method. You shouldn&#039;t need to call this method directly.&lt;br /&gt;
==== link ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$link = html_link::make(new moodle_url(&#039;http://domain.com/index.php&#039;, array(&#039;id&#039; =&amp;gt; 2, &#039;action&#039; =&amp;gt; &#039;browse&#039;)), &#039;Browse page 2&#039;);&lt;br /&gt;
$link-&amp;gt;add_action(new popup_action(&#039;click&#039;, $link-&amp;gt;url));&lt;br /&gt;
echo $OUTPUT-&amp;gt;link($link)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;a id=&amp;quot;html_link-985165&amp;quot; href=&amp;quot;http://domain.com/index.php?id=2&amp;amp;amp;action=browse&amp;quot;&amp;gt;Browse page 2&amp;lt;/a&amp;gt;&lt;br /&gt;
...&lt;br /&gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot;&amp;gt;&lt;br /&gt;
//&amp;lt;![CDATA[ &lt;br /&gt;
YAHOO.util.Event.addListener(&#039;html_link-985165&#039;, &#039;click&#039;, openpopup, {&amp;quot;url&amp;quot;:&amp;quot;http:\/\/domain.com\/index.php?id=2&amp;amp;action=browse&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;popup&amp;quot;,&amp;quot;options&amp;quot;:&amp;quot;[...]&amp;quot;});&lt;br /&gt;
//]]&amp;gt; &lt;br /&gt;
&amp;lt;/script&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== notification ====&lt;br /&gt;
*By default this function works just like container(), with a default class set to &#039;notifyproblem&#039;.&lt;br /&gt;
*It actually inserts a template token which is interpreted and rendered at a later stage.&lt;br /&gt;
&lt;br /&gt;
==== paging_bar ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$pagingbar = moodle_paging_bar::make(120, 3, 20, &#039;http://domain.com/index.php&#039;);&lt;br /&gt;
// Optionally : $pagingbar-&amp;gt;pagevar = &#039;mypage&#039;;&lt;br /&gt;
echo $OUTPUT-&amp;gt;paging_bar($pagingbar);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;div class=&amp;quot;paging&amp;quot;&amp;gt;&lt;br /&gt;
  Page: (&lt;br /&gt;
  &amp;lt;a class=&amp;quot;previous&amp;quot; href=&amp;quot;http://domain.com/index.php?page=2&amp;quot;&amp;gt;Previous&amp;lt;/a&amp;gt;&lt;br /&gt;
  )   &lt;br /&gt;
  &amp;lt;a href=&amp;quot;http://domain.com/index.php?page=0&amp;quot;&amp;gt;1&amp;lt;/a&amp;gt;&lt;br /&gt;
  &amp;lt;a href=&amp;quot;http://domain.com/index.php?page=1&amp;quot;&amp;gt;2&amp;lt;/a&amp;gt;&lt;br /&gt;
  &amp;lt;a href=&amp;quot;http://domain.com/index.php?page=2&amp;quot;&amp;gt;3&amp;lt;/a&amp;gt;&lt;br /&gt;
    4  &lt;br /&gt;
  &amp;lt;a href=&amp;quot;http://domain.com/index.php?page=4&amp;quot;&amp;gt;5&amp;lt;/a&amp;gt;&lt;br /&gt;
  &amp;lt;a href=&amp;quot;http://domain.com/index.php?page=5&amp;quot;&amp;gt;6&amp;lt;/a&amp;gt;&lt;br /&gt;
    (&lt;br /&gt;
  &amp;lt;a class=&amp;quot;next&amp;quot; href=&amp;quot;http://domain.com/index.php?page=4&amp;quot;&amp;gt;Next&amp;lt;/a&amp;gt;&lt;br /&gt;
  )&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== radio ====&lt;br /&gt;
==== select ====&lt;br /&gt;
*This method depends heavily on how the passed component is configured, so see [[Output_API#html_select]] For a detailed description&lt;br /&gt;
&lt;br /&gt;
==== select_option ====&lt;br /&gt;
*Used internally by select(), you shouldn&#039;t need to call this directly.&lt;br /&gt;
&lt;br /&gt;
==== spacer ====&lt;br /&gt;
==== table ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$table = new html_table();&lt;br /&gt;
$table-&amp;gt;head = array(&#039;Student&#039;, &#039;Grade&#039;, &#039;Comments&#039;);&lt;br /&gt;
$table-&amp;gt;data = array(&lt;br /&gt;
    array(&#039;Harry Potter&#039;, &#039;76%&#039;, &#039;Getting better&#039;),&lt;br /&gt;
    array(&#039;Rincewind&#039;, &#039;89%&#039;, &#039;Lucky as usual&#039;),&lt;br /&gt;
    array(&#039;Elminster Aumar&#039;, &#039;100%&#039;, &#039;Easy when you know everything!&#039;)&lt;br /&gt;
);&lt;br /&gt;
echo html_writer::table($table);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;table class=&amp;quot;generaltable&amp;quot;&amp;gt;&lt;br /&gt;
  &amp;lt;thead&amp;gt;&lt;br /&gt;
    &amp;lt;tr&amp;gt;&lt;br /&gt;
      &amp;lt;th class=&amp;quot;header c0&amp;quot; scope=&amp;quot;col&amp;quot; style=&amp;quot;white-space: nowrap;&amp;quot;&amp;gt;Student&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th class=&amp;quot;header c1&amp;quot; scope=&amp;quot;col&amp;quot; style=&amp;quot;white-space: nowrap;&amp;quot;&amp;gt;Grade&amp;lt;/th&amp;gt;&lt;br /&gt;
      &amp;lt;th class=&amp;quot;header c2 lastcol&amp;quot; scope=&amp;quot;col&amp;quot; style=&amp;quot;white-space: nowrap;&amp;quot;&amp;gt;Comments&amp;lt;/th&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
  &amp;lt;/thead&amp;gt;&lt;br /&gt;
  &amp;lt;tbody&amp;gt;&lt;br /&gt;
    &amp;lt;tr class=&amp;quot;r0&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;Harry Potter&amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;76%&amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;Getting better&amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr class=&amp;quot;r1&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;Rincewind&amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;89%&amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;Lucky as usual&amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
    &amp;lt;tr class=&amp;quot;r0 lastrow&amp;quot;&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;Elminster Aumar&amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;100%&amp;lt;/td&amp;gt;&lt;br /&gt;
      &amp;lt;td class=&amp;quot;cell&amp;quot;&amp;gt;Easy when you know everything!&amp;lt;/td&amp;gt;&lt;br /&gt;
    &amp;lt;/tr&amp;gt;&lt;br /&gt;
  &amp;lt;/tbody&amp;gt;&lt;br /&gt;
&amp;lt;/table&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== textfield ====&lt;br /&gt;
==== user_picture ====&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$user = new stdClass();&lt;br /&gt;
$user-&amp;gt;id = 1;&lt;br /&gt;
$userpic = new moodle_user_picture();&lt;br /&gt;
$userpic-&amp;gt;user = $user;&lt;br /&gt;
$userpic-&amp;gt;courseid = 1;&lt;br /&gt;
&lt;br /&gt;
echo $OUTPUT-&amp;gt;user_picture($userpic);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Outputs:&lt;br /&gt;
&amp;lt;code html4strict&amp;gt;&lt;br /&gt;
&amp;lt;img class=&amp;quot;image&amp;quot; style=&amp;quot;height: 35px; width: 35px;&amp;quot; alt=&amp;quot;Picture of Admin User&amp;quot; src=&amp;quot;http://enterprise/cvs_moodle_head/pix/u/f2.png&amp;quot;/&amp;gt;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== cli_core_renderer ===&lt;br /&gt;
&lt;br /&gt;
== Actions ==&lt;br /&gt;
*Component actions are objects that represent Moodle&#039;s response to a user&#039;s action on a component.&lt;br /&gt;
*These objects bind to a moodle_html_component or one of its subclasses.&lt;br /&gt;
*The renderers are responsible for interpreting these actions and generating the appropriate Javascript code.&lt;br /&gt;
&lt;br /&gt;
=== component_action ===&lt;br /&gt;
*This is the base class for all component actions. It includes the name of the event (click, change, keydown etc.), the name of the Javascript function to be called, and an optional array of arguments to pass to the JS function.&lt;br /&gt;
*&#039;&#039;&#039;Important!&#039;&#039;&#039;: the JS function called by this event handler will always receive two arguments: &amp;quot;event&amp;quot; and &amp;quot;args&amp;quot;. &lt;br /&gt;
**The first is a DOM event object and can be used within the function to get the element on which the action was performed, and get information about the event (such as which key was pressed). &lt;br /&gt;
**The second argument (args) is an object with named parameters (a &amp;quot;hash&amp;quot;) that includes the optional JS arguments you defined in the component_action instantiation.&lt;br /&gt;
*Any component which receives an action (through the moodle_html_component::add_action($action) method) needs to be given a unique DOM id attribute. If you do not specify it, one will be automatically generated for you.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$link = new action_link();&lt;br /&gt;
$link-&amp;gt;url = new moodle_url(&#039;/index.php&#039;, array(&#039;id&#039; =&amp;gt; 2, &#039;delete&#039; =&amp;gt; 5));&lt;br /&gt;
$link-&amp;gt;text = &#039;Delete this website&#039;;&lt;br /&gt;
&lt;br /&gt;
$link-&amp;gt;add_action(&#039;click&#039;, &#039;confirm_dialog&#039;, array(&#039;message&#039; =&amp;gt; &#039;Are you sure?&#039;));&lt;br /&gt;
// OR&lt;br /&gt;
$action = new component_action(&#039;click&#039;, &#039;confirm_dialog&#039;, array(&#039;message&#039; =&amp;gt; &#039;Are you REALLY sure?&#039;));&lt;br /&gt;
$link-&amp;gt;add_action($action);&lt;br /&gt;
&lt;br /&gt;
echo $OUTPUT-&amp;gt;link($link);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
*Actions cannot yet be stacked in a component. This means that the above code will behave erratically because we are setting two actions for the same event. It is better to write a custom, more complex JS function than to try to bind several event handlers to the same component.&lt;br /&gt;
&lt;br /&gt;
=== popup_action ===&lt;br /&gt;
*This action opens up a new window using the given $url value.&lt;br /&gt;
*It has a $params associative array with the arguments to the JS window.open() function. It has sensible defaults, but you can override them if necessary.&lt;br /&gt;
&lt;br /&gt;
== Factories ==&lt;br /&gt;
&lt;br /&gt;
== Theme Config ==&lt;br /&gt;
&lt;br /&gt;
== XHTML Container Stack ==&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous functions ==&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[How_Moodle_outputs_HTML]]&lt;br /&gt;
* [[Migrating your code to the 2.0 rendering_API]]&lt;br /&gt;
* [[Outputting HTML in 2.0]]&lt;br /&gt;
* [[Theme_changes]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=AJAX&amp;diff=50963</id>
		<title>AJAX</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=AJAX&amp;diff=50963"/>
		<updated>2016-10-04T07:06:14Z</updated>

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

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

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

		<summary type="html">&lt;p&gt;Libertymoodle: /* CORS */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Feedback here please==&lt;br /&gt;
&lt;br /&gt;
What is the point of the moodle_ prefix? I think it is just a waste of space and should be deleted.--[[User:Tim Hunt|Tim Hunt]] 18:38, 18 August 2011 (WST)&lt;br /&gt;
&lt;br /&gt;
The table in the &#039;&#039;&#039;Web service protocols&#039;&#039;&#039; section has a column called &amp;quot;CORS&amp;quot;. What is &amp;quot;CORS&amp;quot;? Is it http://www.w3.org/TR/cors/? --[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 14:21, 18 May 2016 (AWST)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=49891</id>
		<title>GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=49891"/>
		<updated>2016-04-26T15:23:35Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;An overview of the Google Summer of Code 2016 projects for Moodle.&lt;br /&gt;
&lt;br /&gt;
==tool_pluginkenobi: guide to plugin creation==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2024009&amp;amp;course=5 Alexandru Elisei]&lt;br /&gt;
* Mentor: David Mudrak&lt;br /&gt;
&lt;br /&gt;
==Adding search to more Moodle components==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2039167&amp;amp;course=5 Devang Gaur]&lt;br /&gt;
* Mentor: David Monllaó&lt;br /&gt;
&lt;br /&gt;
==Atto image resize/crop/rotate==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=1953983&amp;amp;course=5 Joey Andres]&lt;br /&gt;
* Mentor: Mark Nelson&lt;br /&gt;
&lt;br /&gt;
==Add support to end-to-end testing in the Mobile app==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2065840&amp;amp;course=5 Supun Wanniarachchi]&lt;br /&gt;
* Mentor: Juan Leyva&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
[http://www.moodleworld.com/moodle-announces-gsoc-participants-gsoc-summerofcode-moodle/ Moodle announces GSoC participants]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:GSOC/2016&amp;diff=49890</id>
		<title>Talk:GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:GSOC/2016&amp;diff=49890"/>
		<updated>2016-04-26T15:20:59Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Deleted comment. Should have googled before adding this comment */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=49889</id>
		<title>GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=49889"/>
		<updated>2016-04-26T15:18:05Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;An overview of the Google Summer of Code 2016 projects for Moodle.&lt;br /&gt;
&lt;br /&gt;
==tool_pluginkenobi: guide to plugin creation==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2024009&amp;amp;course=5 Alexandru Elisei]&lt;br /&gt;
* Mentor: David Mudrak&lt;br /&gt;
&lt;br /&gt;
==Adding search to more Moodle components==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2039167&amp;amp;course=5 Devang Gaur]&lt;br /&gt;
* Mentor: David Monllaó&lt;br /&gt;
&lt;br /&gt;
==Atto image resize/crop/rotate==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=1953983&amp;amp;course=5 Joey Andres]&lt;br /&gt;
* Mentor: Mark Nelson&lt;br /&gt;
&lt;br /&gt;
==Add support to end-to-end testing in the Mobile app==&lt;br /&gt;
&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2065840&amp;amp;course=5 Supun Wanniarachchi]&lt;br /&gt;
* Mentor: Juan Leyva&lt;br /&gt;
&lt;br /&gt;
===See Also===&lt;br /&gt;
[http://www.moodleworld.com/moodle-announces-gsoc-participants-gsoc-summerofcode-moodle/ Moodle announces GSoC participants]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:GSOC/2016&amp;diff=49888</id>
		<title>Talk:GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:GSOC/2016&amp;diff=49888"/>
		<updated>2016-04-26T15:09:06Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* More info */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== tool_pluginkenobi ==&lt;br /&gt;
The tool_pluginkenobi project looks interesting! Can you provide more details.&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 23:08, 26 April 2016 (AWST)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:lib/formslib.php_Usage&amp;diff=49750</id>
		<title>Talk:lib/formslib.php Usage</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:lib/formslib.php_Usage&amp;diff=49750"/>
		<updated>2016-04-01T14:02:28Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Doc needs clarity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The sample code on this page refers to &#039;&#039;&#039;$fromform&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
What is &#039;&#039;&#039;$fromform&#039;&#039;&#039; and where is it defined?&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Form_API&amp;diff=49749</id>
		<title>Talk:Form API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Form_API&amp;diff=49749"/>
		<updated>2016-04-01T13:54:47Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Doc needs clarity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage ==&lt;br /&gt;
This section says: &amp;quot;For creating a form in moodle, you have to create class extending moodleform class&amp;quot;, but WHERE do you create this class? Which .php file? Is it simplehtml_form.php?&lt;br /&gt;
&lt;br /&gt;
Below the &amp;quot;class simplehtml_form extends moodleform&amp;quot; sample code the doc then says: &amp;quot;Then instantiate form (in this case simplehtml_form) on your page.&amp;quot; Where do you instantiate the form? In the view.php page?&lt;br /&gt;
&lt;br /&gt;
Lastly, where do you put the code that processes and saves the form data when the form is submitted?&lt;br /&gt;
&lt;br /&gt;
The documentation should be clear about where you should put all the different sections of code.&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Form_API&amp;diff=49748</id>
		<title>Talk:Form API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Form_API&amp;diff=49748"/>
		<updated>2016-04-01T13:44:23Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Doc needs clarity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage ==&lt;br /&gt;
This section says: &amp;quot;For creating a form in moodle, you have to create class extending moodleform class&amp;quot;, but WHERE do you create this class? Which .php file? The documentation should be clear about where you should put all the different sections of code.&lt;br /&gt;
Where do you put the &amp;quot;class simplehtml_form extends moodleform...&amp;quot; code? Where do you put the code that processes the form data when the form is submitted?&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Form_API&amp;diff=49747</id>
		<title>Talk:Form API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Form_API&amp;diff=49747"/>
		<updated>2016-04-01T13:41:41Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Doc needs clarity */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Usage ==&lt;br /&gt;
This section says: &amp;quot;For creating a form in moodle, you have to create class extending moodleform class&amp;quot;, but WHERE do you create this class? Which .php file?&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Usage&amp;diff=49575</id>
		<title>lib/formslib.php Usage</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=lib/formslib.php_Usage&amp;diff=49575"/>
		<updated>2016-03-03T13:05:31Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: Undo revision 49552 by Nadavkav (talk) - It&amp;#039;s better to link to the Internet Archive copy of the midnighthax.com page instead of deleting the link.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Formslib}}&lt;br /&gt;
==Usage of Formslib==&lt;br /&gt;
&lt;br /&gt;
There are many phpdoc style comments in lib/formslib.php&lt;br /&gt;
&lt;br /&gt;
course/edit.php and the included course/edit_form.php provide a good example of usage of this library.&lt;br /&gt;
&lt;br /&gt;
Also see the PEAR docs for [http://pear.php.net/package/HTML_QuickForm/ HTML_QuickForm docs] I found this [http://pear.php.net/manual/en/package.html.html-quickform.tutorial.php quick tutorial] and this [http://web.archive.org/web/20130630141100/http://www.midnighthax.com/quickform.php slightly longer one] particularly useful (Note: the original docs on the midnighthax.com domain no longer exist, so this link now points to the Internet Archive copy of the site).&lt;br /&gt;
&lt;br /&gt;
We created some special wrapper functions for moodle. Function $mform-&amp;gt;get_data() returns an object with the contents of the submitted data or returns null if no data has been submitted or validation fails.&lt;br /&gt;
&lt;br /&gt;
===Basic Usage in A Normal Page===&lt;br /&gt;
&lt;br /&gt;
Generally the structure of a page with a form on it looks like this :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;pathtoformdescription&#039;);&lt;br /&gt;
// You will process some page parameters at the top here and get the info about&lt;br /&gt;
// what instance of your module and what course you&#039;re in etc. Make sure you&lt;br /&gt;
// include hidden variable in your forms which have their defaults set in set_data&lt;br /&gt;
// which pass these variables from page to page.&lt;br /&gt;
&lt;br /&gt;
// Setup $PAGE here.&lt;br /&gt;
&lt;br /&gt;
$mform = new yourmod_formfunction_form();//name of the form you defined in file above.&lt;br /&gt;
// Default &#039;action&#039; for form is strip_querystring(qualified_me()).&lt;br /&gt;
&lt;br /&gt;
// Set the initial values, for example the existing data loaded from the database.&lt;br /&gt;
// (an array of name/value pairs that match the names of data elements in the form.&lt;br /&gt;
// You can also use an object)&lt;br /&gt;
$mform-&amp;gt;set_data($toform);&lt;br /&gt;
&lt;br /&gt;
if ($mform-&amp;gt;is_cancelled()) {&lt;br /&gt;
    // You need this section if you have a cancel button on your form&lt;br /&gt;
    // here you tell php what to do if your user presses cancel&lt;br /&gt;
    // probably a redirect is called for!&lt;br /&gt;
    // PLEASE NOTE: is_cancelled() should be called before get_data().&lt;br /&gt;
    redirect($returnurl);&lt;br /&gt;
&lt;br /&gt;
} else if ($fromform = $mform-&amp;gt;get_data()) {&lt;br /&gt;
    // This branch is where you process validated data.&lt;br /&gt;
    // Do stuff ...&lt;br /&gt;
&lt;br /&gt;
    // Typically you finish up by redirecting to somewhere where the user&lt;br /&gt;
    // can see what they did.&lt;br /&gt;
    redirect($nexturl);&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
$mform-&amp;gt;display();&lt;br /&gt;
echo $OUTPUT-&amp;gt;footer();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
You are encouraged to look at &#039;&#039;&#039;lib/formslib.php&#039;&#039;&#039; to see what additional functions and parameters are available. Available functions are well commented.&lt;br /&gt;
&lt;br /&gt;
===Defining Your Form Class===&lt;br /&gt;
&lt;br /&gt;
The form class tells us about the structure of the form. You are encouraged to put this in a file called {function}_form.php probably in the same folder in which the page that uses it is located. The name of your class should be {modname}_{function}_form eg. forum_post_form or course_edit_form. These classes will extend class moodleform.&lt;br /&gt;
&lt;br /&gt;
Note the name you give the class is used as the id attribute of your form in html (any trailing &#039;_form&#039; is chopped off&#039;). Your form class name should be unique in order for it to be selectable in CSS by theme designers who may want to tweak the css just for that form.&lt;br /&gt;
&lt;br /&gt;
====definition()====&lt;br /&gt;
&lt;br /&gt;
[[lib/formslib.php_Form_Definition|Help is here for defining your form]] by defining a function definition() in your form class that sets up your form structure.&lt;br /&gt;
&lt;br /&gt;
===Use in Activity Modules Add / Update Forms===&lt;br /&gt;
&lt;br /&gt;
Syntax is the same in activity modules to create your update / add page. We are still supporting mod.html but if you want to use the new formslib then you can in Moodle 1.8 just include in your module directory the file mod_form.php instead of mod.html and it will be automatically detected. Inside this file you define a class with class name &#039;{modname}__mod_form&#039; which extends the class &#039;moodleform_mod&#039;. See many examples of the core modules which have been converted to use formslib already.&lt;br /&gt;
&lt;br /&gt;
====defaults_preprocessing====&lt;br /&gt;
&lt;br /&gt;
For activity modules you use the same syntax to define your form. You may also want to override method defaults_preprocessing this can be used to take the data from the data base and tell the form how to fill out defaults in the form with this data. For example in the forum module in forum/mod_form.php we needed to tick an enable check box if a date had been selected in the date select. Normally data is loaded from the database and directly loaded into form fields with the same name as the database record you only need to use defaults_preprocessing if there isn&#039;t this one to one relationship. Another example is the lesson/mod_form.php which takes the data from the database and unserializes it. choice/mod_form.php shows an exampe of loading data from another db table referred to by a foreign key, to include in the form.&lt;br /&gt;
&lt;br /&gt;
====Post Processing Still Done in lib.php Functions====&lt;br /&gt;
&lt;br /&gt;
Post processing of data is done in lib.php functions modname_add_instance and modname_update_instance after the data has been validated. When migrating a form often little changes need to be made in the post processing. An exception is that date and date_time_selector fields automatically have their submitted data turned into timestamps so you don&#039;t need to do this in your add and update functions anymore.&lt;br /&gt;
&lt;br /&gt;
====Automatically Including Standard Activity Module Form Elements====&lt;br /&gt;
&lt;br /&gt;
Standard activity module form elements are automatically included using the moodleform_mod method standard_coursemodule_elements(). The default is to include a visibility and groupsmode select box and to include all necessary hidden fields. You can pass a parameter false to tell the method that your module doesn&#039;t support groups and so you don&#039;t want the groupsmode select button.&lt;br /&gt;
&lt;br /&gt;
[[Category:Formslib]]&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Theme_checklist&amp;diff=49325</id>
		<title>Theme checklist</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Theme_checklist&amp;diff=49325"/>
		<updated>2016-02-01T05:58:59Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Typos */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Themes}}So, you think your theme is finished? Well, Moodle is a big complex system and there are lots of obscure corners that you might not know about. This page lists lots of things that you might have missed when working on your theme. To be sure your theme is really complete, you need to check these out.&lt;br /&gt;
&lt;br /&gt;
== Accessible colours ==&lt;br /&gt;
&lt;br /&gt;
Are the colours you have chosen accessible?  Is there a reasonable contrast difference between them?&lt;br /&gt;
&lt;br /&gt;
== All the different forms of the front page ==&lt;br /&gt;
&lt;br /&gt;
Depending on how many courses there are in your Moodle site, and how many of them the current user is enrolled in, the [[:en:Front_page|front page]] looks different. Have you tested all the different ways it can look?&lt;br /&gt;
&lt;br /&gt;
== Big report tables ==&lt;br /&gt;
&lt;br /&gt;
The [[:en:Gradebook|grader report]], and other similar reports like the quiz reports, are very big tables that don&#039;t fit on one screen. How does your theme cope. Is it easy for the teacher to scroll sideways to see all the data?&lt;br /&gt;
&lt;br /&gt;
== Clean install ==&lt;br /&gt;
&lt;br /&gt;
Have you installed and un-installed the theme on a &#039;pure&#039; installation?  That is an installation with no other contributed plugins.  This allows you to check for unintentional dependencies.&lt;br /&gt;
&lt;br /&gt;
== Code checker ==&lt;br /&gt;
&lt;br /&gt;
[https://moodle.org/plugins/view.php?plugin=local_codechecker Code checker] checks your code against the Moodle [https://docs.moodle.org/dev/Coding coding standards].  It is a useful tool for spotting issues and making your code readable to all who are familiar with the core code.  Do not take all messages literally, use your common sense and make changes that are sensible.&lt;br /&gt;
&lt;br /&gt;
== Dependencies ==&lt;br /&gt;
&lt;br /&gt;
Have you specified the correct dependencies for both parent themes and Moodle in the &#039;[https://docs.moodle.org/dev/version.php version.php]&#039; file?&lt;br /&gt;
&lt;br /&gt;
== Fake blocks ==&lt;br /&gt;
&lt;br /&gt;
While you are looking at the quiz, pay attention to the [[:en:Using_Quiz|Quiz navigation block]]. This is not a normal block that teachers or admins can add or remove, it is a &#039;Fake block&#039; that looks like any other block but is part of the Moodle UI. Are you happy with where it appears, and how it looks?&lt;br /&gt;
&lt;br /&gt;
Other parts of Moodle that use fake blocks are the [[:en:Lesson_module|Lesson activity]] and [[:en:Calendar|the calendar UI]].&lt;br /&gt;
&lt;br /&gt;
Fake blocks are attached to the first region or the &#039;defaultregion&#039; in the &#039;regions&#039; array for the &#039;layout&#039; in the &#039;layouts&#039; array in the &#039;config.php&#039; file.  So if the order is (&#039;side-pre&#039;, &#039;side-post&#039;) and you want fake blocks to be in &#039;side-post&#039; change the &#039;defaultregion&#039; to &#039;side-post&#039; and the &#039;regions&#039; array to (&#039;side-post&#039;, &#039;side-pre&#039;).&lt;br /&gt;
&lt;br /&gt;
===Adding a fake block to each pagelayout in your theme:===&lt;br /&gt;
(add following function to theme/yourtheme/lib.php)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function theme_yourtheme_get_html_for_settings(renderer_base $output, moodle_page $page) function:&lt;br /&gt;
&lt;br /&gt;
$bc = new block_contents();&lt;br /&gt;
$bc-&amp;gt;title = &#039;fake title&#039;;&lt;br /&gt;
$bc-&amp;gt;attributes[&#039;class&#039;] = &#039;fakeblock&#039;;&lt;br /&gt;
$bc-&amp;gt;content = &#039;fake content&#039;;&lt;br /&gt;
$page-&amp;gt;blocks-&amp;gt;add_fake_block($bc, &#039;side-pre&#039;);&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Instructions ==&lt;br /&gt;
&lt;br /&gt;
Have you provided a &#039;readme&#039; file containing: Install instructions, un-install instructions, version history and contact details for when things go wrong.&lt;br /&gt;
&lt;br /&gt;
== License ==&lt;br /&gt;
&lt;br /&gt;
Is all code GPLv3 (or compatible) licensed?&lt;br /&gt;
&lt;br /&gt;
== Maturity ==&lt;br /&gt;
&lt;br /&gt;
Have you correctly stated the maturity of the theme in the &#039;[https://docs.moodle.org/dev/version.php version.php]&#039; file?  This gives users and idea of how stable the code is.&lt;br /&gt;
&lt;br /&gt;
== Quiz &#039;secure&#039; pop-up ==&lt;br /&gt;
&lt;br /&gt;
When a quiz set to [[:en:Quiz_settings#Extra_restrictions_on_attempts|Full screen pop-up with some JavaScript security]] then the page uses a special &#039;secure&#039; layout template that should have minimal headers or links.&lt;br /&gt;
&lt;br /&gt;
== Readable fonts ==&lt;br /&gt;
&lt;br /&gt;
Are the fonts you have chosen readable?  Will they be difficult to read on small devices?&lt;br /&gt;
&lt;br /&gt;
== Right-to-left languages ==&lt;br /&gt;
&lt;br /&gt;
In languages like Hebrew or Farsi, lots of things that you made left-aligned probably need to be right-aligned instead. Moodle adds .dir-rtl or .dir-ltr class to the body element, which you can use in CSS rules.&lt;br /&gt;
&lt;br /&gt;
== Responsive ==&lt;br /&gt;
&lt;br /&gt;
Have you tested your theme for responsiveness on small devices?  Try resizing the browser window and see how it reacts.&lt;br /&gt;
&lt;br /&gt;
== Theme developer mode ==&lt;br /&gt;
&lt;br /&gt;
When &#039;Theme developer mode&#039; is &#039;on&#039;, all of the CSS files are sent individually.  When it is &#039;off&#039;, they are all combined together.  This can lead to some issues.  Check that your theme works with &#039;Theme designer mode off&#039;.&lt;br /&gt;
&lt;br /&gt;
== ... please add more things here in alphabetical order ... ==&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Webservice_protocols&amp;diff=49126</id>
		<title>Talk:Webservice protocols</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Webservice_protocols&amp;diff=49126"/>
		<updated>2015-12-07T19:34:38Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: Provide examples of WS calls&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==webservice/myprotocol/server.php==&lt;br /&gt;
This topic says: &amp;quot;The web service clients will call this file with the web service function name/parameters and the web service token.&amp;quot; Can you provide some examples of this call so we can see what it looks like?&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Luis_de_Vasconcelos&amp;diff=48890</id>
		<title>User:Luis de Vasconcelos</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Luis_de_Vasconcelos&amp;diff=48890"/>
		<updated>2015-10-31T21:44:42Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Moodle sysadmin and developer at Liberty Life, South Africa&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=User:Petr_%C5%A0koda_(%C5%A1ko%C4%8F%C3%A1k)&amp;diff=48889</id>
		<title>User:Petr Škoda (škoďák)</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=User:Petr_%C5%A0koda_(%C5%A1ko%C4%8F%C3%A1k)&amp;diff=48889"/>
		<updated>2015-10-31T21:36:39Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* independent developer working for Totara Learning Solutions&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Testing_of_integrated_issues&amp;diff=46868</id>
		<title>Talk:Testing of integrated issues</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Testing_of_integrated_issues&amp;diff=46868"/>
		<updated>2014-11-20T09:27:57Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: iTeam&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== iTeam ==&lt;br /&gt;
Who or what is the &amp;quot;iTeam&amp;quot;?&lt;br /&gt;
This article shouldn&#039;t assume that the reader is familiar with HQ terms.&lt;br /&gt;
&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 17:27, 20 November 2014 (AWST)&lt;br /&gt;
&lt;br /&gt;
== Providing instructions for testers should be compulsory for HQ developers ==&lt;br /&gt;
&lt;br /&gt;
Suggestion: Either MDL or PULL ticket must provide exact instructions for testers how the patch can be tested from user&#039;s perspective. Testers are not expected to study the source code change to construct the test case on their own. If the PULL request comes from an HQ employee and steps to test are not provided, the test would fail automatically. --[[User:David Mudrak|David Mudrak]] 14:03, 17 January 2011 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Schedule==&lt;br /&gt;
&lt;br /&gt;
Suggested timing:&lt;br /&gt;
&lt;br /&gt;
* Integration reviewing - Monday up to Tuesday 12 noon UTC&lt;br /&gt;
* Testing - Tuesday up to Wednesday 12 noon UTC&lt;br /&gt;
&lt;br /&gt;
Once the last pull request for the week is reviewed, the QA Testing Site can be updated from the integration server. --[[User:Helen Foster|Helen Foster]] 14:52, 19 January 2011 (UTC)&lt;br /&gt;
&lt;br /&gt;
==Broken Link==&lt;br /&gt;
The &amp;quot;testing process&amp;quot; section on https://docs.moodle.org/dev/Testing_of_integrated_issues links to https://tracker.moodle.org/browse/PULL but that https://tracker.moodle.org/browse/PULL address returns a &amp;quot;Project Does Not Exist&amp;quot; error. What is the current URL?&lt;br /&gt;
&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 20:43, 1 July 2013 (WST)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Migrating_logging_calls_in_plugins&amp;diff=46673</id>
		<title>Migrating logging calls in plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Migrating_logging_calls_in_plugins&amp;diff=46673"/>
		<updated>2014-11-03T13:12:52Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* See also */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is aimed to assist developers in replacing existing &#039;&#039;&#039;add_to_log()&#039;&#039;&#039; and &#039;&#039;&#039;events_trigger()&#039;&#039;&#039; calls with events. This can be implemented in Moodle 2.6 and will be required in 2.7.&lt;br /&gt;
&lt;br /&gt;
As a quick reminder: [[Event 2|new events]] were introduced in Moodle 2.6, a new [[Logging 2|logging system]] is being introduced in Moodle 2.7. The &#039;&#039;&#039;add_to_log()&#039;&#039;&#039; function will be deprecated, but the existing log table will still be present with existing data intact. This original logging is now called &#039;&#039;legacy logging&#039;&#039;. The new and legacy logging may coexist in the legacy logging system for purposes of transition, but this is not recommended for performance reasons. When replacing calls to add_to_log() with the triggering of an event, developers must ensure that they also generate an entry for the legacy log. It will only be used if the legacy log is enabled, since it may be enabled on systems that continue to use custom reports relying on presence of the legacy log table and it may take time to migrate such reports.&lt;br /&gt;
&lt;br /&gt;
== Quick guide ==&lt;br /&gt;
&lt;br /&gt;
If you are replacing common add_to_log() calls such as &amp;quot;view&amp;quot; and &amp;quot;view all&amp;quot; in mod/XXX/view.php and mod/XXX/index.php, see below. Otherwise do the following.&lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choose a name for the event ===&lt;br /&gt;
&lt;br /&gt;
Names should follow the syntax OBJECT_VERB, for example &amp;quot;entry_added&amp;quot;, &amp;quot;work_submitted&amp;quot;, etc. It does not need to include a plugin name because this can be obtained from the PHP class namespace. See [[Event 2|the events documentation]] for more details about event name; specifically, there is a restricted [[Event 2#Verb list|list of available verbs]].&lt;br /&gt;
&lt;br /&gt;
Define a language string for the event name in &#039;&#039;&#039;YOURPLUGINDIR/lang/en/FULLPLUGINNAME.php&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;eventEVENTNAME] = &#039;Something has happened&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Create event class ===&lt;br /&gt;
&lt;br /&gt;
For each event you must create an event class in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/EVENTNAME.php&#039;&#039;&#039;, with the following format.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * The EVENTNAME event.&lt;br /&gt;
 *&lt;br /&gt;
 * @package    FULLPLUGINNAME&lt;br /&gt;
 * @copyright  2014 YOUR NAME&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
/**&lt;br /&gt;
 * The EVENTNAME event class.&lt;br /&gt;
 *&lt;br /&gt;
 * @property-read array $other {&lt;br /&gt;
 *      Extra information about event.&lt;br /&gt;
 *&lt;br /&gt;
 *      - PUT INFO HERE&lt;br /&gt;
 * }&lt;br /&gt;
 *&lt;br /&gt;
 * @since     Moodle MOODLEVERSION&lt;br /&gt;
 * @copyright 2014 YOUR NAME&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 **/&lt;br /&gt;
class EVENTNAME extends \core\event\base {&lt;br /&gt;
    protected function init() {&lt;br /&gt;
        $this-&amp;gt;data[&#039;crud&#039;] = &#039;c&#039;; // c(reate), r(ead), u(pdate), d(elete)&lt;br /&gt;
        $this-&amp;gt;data[&#039;edulevel&#039;] = self::LEVEL_PARTICIPATING;&lt;br /&gt;
        $this-&amp;gt;data[&#039;objecttable&#039;] = &#039;...&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public static function get_name() {&lt;br /&gt;
        return get_string(&#039;eventEVENTNAME&#039;, &#039;FULLPLUGINNAME&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_description() {&lt;br /&gt;
        return &amp;quot;The user with id {$this-&amp;gt;userid} created ... ... ... with id {$this-&amp;gt;objectid}.&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_url() {&lt;br /&gt;
        return new \moodle_url(&#039;....&#039;, array(&#039;parameter&#039; =&amp;gt; &#039;value&#039;, ...));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_legacy_logdata() {&lt;br /&gt;
        // Override if you are migrating an add_to_log() call.&lt;br /&gt;
        return array($this-&amp;gt;courseid, &#039;PLUGINNAME&#039;, &#039;LOGACTION&#039;,&lt;br /&gt;
            &#039;...........&#039;,&lt;br /&gt;
            $this-&amp;gt;objectid, $this-&amp;gt;contextinstanceid);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public static function get_legacy_eventname() {&lt;br /&gt;
        // Override ONLY if you are migrating events_trigger() call.&lt;br /&gt;
        return &#039;MYPLUGIN_OLD_EVENT_NAME&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function get_legacy_eventdata() {&lt;br /&gt;
        // Override if you migrating events_trigger() call.&lt;br /&gt;
        $data = new \stdClass();&lt;br /&gt;
        $data-&amp;gt;id = $this-&amp;gt;objectid;&lt;br /&gt;
        $data-&amp;gt;userid = $this-&amp;gt;relateduserid;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Trigger the event instead of add_to_log() ===&lt;br /&gt;
&lt;br /&gt;
Replace the add_to_log() with an event trigger. The following is a common example of an event trigger inside an activity module.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
add_to_log($course-&amp;gt;id, &#039;PLUGINNAME&#039;, &#039;LOGACTION&#039;, &#039;...........&#039;, $objid, $cmid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...becomes...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\EVENTNAME::create(array(&lt;br /&gt;
    &#039;objectid&#039; =&amp;gt; $objid,&lt;br /&gt;
    &#039;context&#039; =&amp;gt; context_module::instance($cmid)&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to trigger event multiple times in the code, or just prefer shorter syntax, you can declare your own static create function in the event class that would populate necessary fields and even add snapshots (see examples in mod_assign). In this case you can triger event in one line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
\FULLPLUGINNAME\event\EVENTNAME::create_from_someobject($someobject)-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 4. Increase the version number in version.php===&lt;br /&gt;
&lt;br /&gt;
The events that exist are only scanned when a plugin is installed or updated. Therefore when you change events, you need to increase the plugin&#039;s version number in its version.php to prompt an upgrade.&lt;br /&gt;
&lt;br /&gt;
== Replacing &#039;view&#039; events in modules ==&lt;br /&gt;
&lt;br /&gt;
Calls to add_to_log() to report a &#039;view&#039; event are usually found in mod/PLUGINNAME/view.php (or in a lib function included by this file) and indicate that a user viewed the module. &lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choosing the name ===&lt;br /&gt;
&lt;br /&gt;
Because this is a common event, the name is already chosen: &#039;&#039;&#039;course_module_viewed&#039;&#039;&#039; and the language string is defined in core.&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Defining class ===&lt;br /&gt;
&lt;br /&gt;
You must create a class for this event in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/course_module_viewed.php&#039;&#039;&#039; with the following format.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
class course_module_viewed extends \core\event\course_module_viewed {&lt;br /&gt;
    protected function init() {&lt;br /&gt;
        $this-&amp;gt;data[&#039;objecttable&#039;] = &#039;PLUGINNAME&#039;;&lt;br /&gt;
        parent::init();&lt;br /&gt;
    }&lt;br /&gt;
    // You might need to override get_url() and get_legacy_log_data() if view mode needs to be stored as well.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Triggering the event ===&lt;br /&gt;
&lt;br /&gt;
This example takes data from $PAGE object but you may substitute this with ids and objects that you have fetched.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\course_module_viewed::create(array(&lt;br /&gt;
    &#039;objectid&#039; =&amp;gt; $PAGE-&amp;gt;cm-&amp;gt;instance,&lt;br /&gt;
    &#039;context&#039; =&amp;gt; $PAGE-&amp;gt;context,&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;add_record_snapshot(&#039;course&#039;, $PAGE-&amp;gt;course);&lt;br /&gt;
// In the next line you can use $PAGE-&amp;gt;activityrecord if you have set it, or skip this line if you don&#039;t have a record.&lt;br /&gt;
$event-&amp;gt;add_record_snapshot($PAGE-&amp;gt;cm-&amp;gt;modname, $activityrecord);&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Step 4. Update version.php===&lt;br /&gt;
Don&#039;t forget to update the plugin version number to prompt an upgrade.&lt;br /&gt;
&lt;br /&gt;
== Replacing &#039;view all&#039; events in modules ==&lt;br /&gt;
&lt;br /&gt;
Calls to add_to_log using &#039;view_all&#039; are usually found in mod/PLUGINNAME/index.php (or in a lib function included by this file). These invents indicate that a user viewed the list of all instances of this module within the course. &lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choosing the name ===&lt;br /&gt;
&lt;br /&gt;
Because this is a common event, the name is already chosen: &#039;&#039;&#039;course_module_instance_list_viewed&#039;&#039;&#039; and the language string is defined in core.&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Defining class ===&lt;br /&gt;
&lt;br /&gt;
You must create a class for this event in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/course_module_instance_list_viewed.php&#039;&#039;&#039; with the following structure.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Triggering the event ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\course_module_instance_list_viewed::create(array(&lt;br /&gt;
    &#039;context&#039; =&amp;gt; context_course::instance($course-&amp;gt;id)&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What to include in the event ==&lt;br /&gt;
&lt;br /&gt;
=== init() and create() ===&lt;br /&gt;
&lt;br /&gt;
Ideally all information needed when initialising and triggering events should already be available without having to run additional queries. Queries run to fill event objects with data will cause additional performance load, which should be avoided. Information that needs to be gathered from the database should be provided by other event methods, which can be called selectively when needed.&lt;br /&gt;
&lt;br /&gt;
As you noticed in the examples above you can specify additional properties either by the overriding the init() method of the event or when calling create(). The first way is used for properties that are always the same for this event, the second is for dynamic properties that may differ when the event is triggered.&lt;br /&gt;
&lt;br /&gt;
Usually you need to include the following properties.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;context&#039;&#039;&#039; or &#039;&#039;&#039;contextid&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| Describes the context where the event took place.&lt;br /&gt;
| If you want to hardcode the system context, do so in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;crud&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| Describes whether the event reflects creation (c), reading (r), updating (u) or deleting (d). This should be a single character string.&lt;br /&gt;
| Most often are specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;edulevel&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| The level of educational value of the event. Can be LEVEL_TEACHING, LEVEL_PARTICIPATING or LEVEL_OTHER.&lt;br /&gt;
| Most often are specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;objecttable&#039;&#039;&#039; and &#039;&#039;&#039;objectid&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| Objecttable is the table that best represents the event object. Usually it is the object where the &amp;quot;CRUD&amp;quot; action was performed. This table is used by events that show the change in one record of one table, which will be the case for the most events.&lt;br /&gt;
| Since &#039;objecttable&#039; is always the same it is usually specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;relateduserid&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| The id of the user affected by the event.&lt;br /&gt;
| Only used if it is easy to identify a single user who is affected by this operation. For example a user who is being graded, a user who receives the message, a user being enrolled, etc. &#039;&#039;&#039;This is NOT the user who performs the action&#039;&#039;&#039; (who is identified in the userid field).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;other&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| Everything else that you may think is important about this event. This property will be serialised and stored by loggers.&lt;br /&gt;
| Include only necessary information. It can be used in get_description(), get_url() and get_legacy_logdata(). This property should only contain an array or scalar value, it &#039;&#039;&#039;can not use objects&#039;&#039;&#039;.&lt;br /&gt;
Example of information stored in &#039;other&#039; can be found in event course_module_deleted:&lt;br /&gt;
* Definition: https://github.com/moodle/moodle/blob/MOODLE_27_STABLE/lib/classes/event/course_module_deleted.php#L71&lt;br /&gt;
* Triggering:https://github.com/moodle/moodle/blob/MOODLE_27_STABLE/course/lib.php#L1737..L1747&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Usually you don&#039;t need to include the following properties as they are deduced by the base class.&lt;br /&gt;
* &#039;userid&#039;: user who performs the action, taken from $USER&lt;br /&gt;
* &#039;courseid&#039;: course affected in the operation, which will be taken from context. It need not be specified at all for events that are not related to a particular course.&lt;br /&gt;
&lt;br /&gt;
See the [[Event_2#Information_contained_in_events|full list of properties]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== get_legacy_logdata() ===&lt;br /&gt;
&lt;br /&gt;
This method is used to add log data to the legacy log. You need only override this method when replacing an add_to_log() call. Since this document is a transition guide from add_to_log() to events, you will most likely need to override this method. This method needs to return an array (with 3-7 elements) that imitates the arguments that used to be passed to the add_to_log() function. From Moodle 2.7, the get_legacy_logdata() method will only be called if legacy logging is enabled through the legacy logging plugin.&lt;br /&gt;
&lt;br /&gt;
=== get_description() and get_url() ===&lt;br /&gt;
&lt;br /&gt;
Most reporting tools will display aggregated event information (for example the count of student logins) so those methods, which describe individual events, are not likely to be called often; they will only be used by detailed reports such as loglive. At the moment, use get_description() to provide a very brief internal description of the action performed, so that it can be used for error recovery like any other system log. The description is hard-coded in English but it may be possible that future versions of Moodle (2.8 or later) will allow the use of translatable language strings. These methods should not make DB queries, access global variables, etc. For example, when a course is renamed or when a user is deleted, do not retrieve the course name or user name, instead simply use their ids. These functions should return exactly the same result whenever they are called, regardless of the environment or state, even after they have been restored from logs. &lt;br /&gt;
&lt;br /&gt;
=== get_legacy_eventname() and get_legacy_eventdata() ===&lt;br /&gt;
&lt;br /&gt;
You will need to override these two functions if you are upgrading events_trigger() calls. These will allow legacy plugins to continue to listen to your new events without upgrading their listeners.&lt;br /&gt;
&lt;br /&gt;
If you need to provide more detailed information to observers, you can choose to:&lt;br /&gt;
* add more information to &#039;other&#039;, but remember that this will be logged and it&#039;s better to keep logs as small as possible;&lt;br /&gt;
* use record snapshots, which are especially useful for delete actions (you can call get_record_snapshot() inside get_legacy_eventdata() and observers are encouraged to get data from snapshots as well);&lt;br /&gt;
* add new properties to your event class and define getter/setter functions, for example set_custom_data() and get_custom_data().&lt;br /&gt;
&lt;br /&gt;
=== add_record_snapshot() ===&lt;br /&gt;
&lt;br /&gt;
A record snapshot can be added for any DB table related to the event. If it is added, it must be an instance of stdClass containing all fields that are present in the corresponding DB table. You must add a record snapshot when you delete something from database. &#039;&#039;&#039;Record snapshots cannot be used from reports, it is intended for event observers only.&#039;&#039;&#039; Usually observers expect a record snapshot identified by &#039;objecttable&#039; and &#039;objectid&#039; but developers may also add snapshots of related tables, i.e. when book chapter is updated the developer may decide to add snapshots of related records in tables book_chapters, book, course_modules and course. &lt;br /&gt;
&lt;br /&gt;
Record snapshots should be added only when you already have an object and do not need to perform any additional DB queries to retrieve it. Otherwise omit it, as the record will be retrieved by get_record_snapshot() automatically, and only if needed. For performance reasons the snapshots are not guaranteed to contain an exact state at the time of event triggering, it may be fetched at any time between the triggering of event and its observation.&lt;br /&gt;
&lt;br /&gt;
== Events DON&#039;Ts ==&lt;br /&gt;
&lt;br /&gt;
Do not put more information in &#039;other&#039; than is needed. For example, do not include a full DB record for delete/create operations or a list of all changed properties in edit operations. If observers are interested in this information, it can requested by calling get_record_snapshot(). Never include large text fields in event data. &#039;&#039;&#039;Please help to keep the log size reasonable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Do NOT use $USER, $COURSE, $PAGE or other global variables when overriding get_* methods (with the exception of get_legacy_eventdata).&lt;br /&gt;
&lt;br /&gt;
Do NOT call $this-&amp;gt;get_record_snapshot() inside the event class (again with the exception of get_legacy_eventdata). If you need additional information for internal functions that cannot be added to existing properties, add it to the &#039;other&#039; property.&lt;br /&gt;
&lt;br /&gt;
Do NOT use $this-&amp;gt;context inside an event class. &#039;&#039;&#039;Remember that methods get_description() and get_url() may be called on events after they have been restored from logs.&#039;&#039;&#039; It is possible that the original context no longer exists when these functions are called. Instead use $this-&amp;gt;contextid, $this-&amp;gt;contextlevel, $this-&amp;gt;contextinstanceid.&lt;br /&gt;
&lt;br /&gt;
== Validation and testing ==&lt;br /&gt;
&lt;br /&gt;
You may notice that the most of events in Moodle also have function validate_data() . You can add this function for your own safety to ensure that you don&#039;t forget to define all required data when triggering event.&lt;br /&gt;
&lt;br /&gt;
Always use developer debugging mode when doing development. A lot of useful build-in validation will only work in development mode.&lt;br /&gt;
&lt;br /&gt;
We highly recommend to cover your events with unit tests. Search in standard plugins for files with the names events_test.php to see examples.&lt;br /&gt;
&lt;br /&gt;
In order to manually test the event you can perform the action and check how it appears in &#039;&#039;&#039;Course Administration &amp;gt; Reports &amp;gt; Logs&#039;&#039;&#039;. Also look up your event in the &#039;&#039;&#039;Site Administration &amp;gt; Reports &amp;gt; Events list&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Installation&amp;quot; of events ==&lt;br /&gt;
&lt;br /&gt;
Remember that you have to bump the plugin version in order to prompt an upgrade so that new events will be &amp;quot;installed&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
The [https://github.com/markn86/moodle-mod_certificate/pull/34 &#039;&#039;&#039;add_to_log deprecated, replace with events&#039;&#039;&#039;] issue on Github illustrates how the deprecated &#039;&#039;&#039;add_to_log()&#039;&#039;&#039; calls in the Certificate Module were upgraded to the new events method.&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Migrating_logging_calls_in_plugins&amp;diff=46672</id>
		<title>Migrating logging calls in plugins</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Migrating_logging_calls_in_plugins&amp;diff=46672"/>
		<updated>2014-11-03T13:10:52Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: Add &amp;#039;See Also&amp;#039; link&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This document is aimed to assist developers in replacing existing &#039;&#039;&#039;add_to_log()&#039;&#039;&#039; and &#039;&#039;&#039;events_trigger()&#039;&#039;&#039; calls with events. This can be implemented in Moodle 2.6 and will be required in 2.7.&lt;br /&gt;
&lt;br /&gt;
As a quick reminder: [[Event 2|new events]] were introduced in Moodle 2.6, a new [[Logging 2|logging system]] is being introduced in Moodle 2.7. The &#039;&#039;&#039;add_to_log()&#039;&#039;&#039; function will be deprecated, but the existing log table will still be present with existing data intact. This original logging is now called &#039;&#039;legacy logging&#039;&#039;. The new and legacy logging may coexist in the legacy logging system for purposes of transition, but this is not recommended for performance reasons. When replacing calls to add_to_log() with the triggering of an event, developers must ensure that they also generate an entry for the legacy log. It will only be used if the legacy log is enabled, since it may be enabled on systems that continue to use custom reports relying on presence of the legacy log table and it may take time to migrate such reports.&lt;br /&gt;
&lt;br /&gt;
== Quick guide ==&lt;br /&gt;
&lt;br /&gt;
If you are replacing common add_to_log() calls such as &amp;quot;view&amp;quot; and &amp;quot;view all&amp;quot; in mod/XXX/view.php and mod/XXX/index.php, see below. Otherwise do the following.&lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choose a name for the event ===&lt;br /&gt;
&lt;br /&gt;
Names should follow the syntax OBJECT_VERB, for example &amp;quot;entry_added&amp;quot;, &amp;quot;work_submitted&amp;quot;, etc. It does not need to include a plugin name because this can be obtained from the PHP class namespace. See [[Event 2|the events documentation]] for more details about event name; specifically, there is a restricted [[Event 2#Verb list|list of available verbs]].&lt;br /&gt;
&lt;br /&gt;
Define a language string for the event name in &#039;&#039;&#039;YOURPLUGINDIR/lang/en/FULLPLUGINNAME.php&#039;&#039;&#039;.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;eventEVENTNAME] = &#039;Something has happened&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Create event class ===&lt;br /&gt;
&lt;br /&gt;
For each event you must create an event class in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/EVENTNAME.php&#039;&#039;&#039;, with the following format.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
// This file is part of Moodle - http://moodle.org/&lt;br /&gt;
//&lt;br /&gt;
// Moodle is free software: you can redistribute it and/or modify&lt;br /&gt;
// it under the terms of the GNU General Public License as published by&lt;br /&gt;
// the Free Software Foundation, either version 3 of the License, or&lt;br /&gt;
// (at your option) any later version.&lt;br /&gt;
//&lt;br /&gt;
// Moodle is distributed in the hope that it will be useful,&lt;br /&gt;
// but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the&lt;br /&gt;
// GNU General Public License for more details.&lt;br /&gt;
//&lt;br /&gt;
// You should have received a copy of the GNU General Public License&lt;br /&gt;
// along with Moodle.  If not, see &amp;lt;http://www.gnu.org/licenses/&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * The EVENTNAME event.&lt;br /&gt;
 *&lt;br /&gt;
 * @package    FULLPLUGINNAME&lt;br /&gt;
 * @copyright  2014 YOUR NAME&lt;br /&gt;
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
/**&lt;br /&gt;
 * The EVENTNAME event class.&lt;br /&gt;
 *&lt;br /&gt;
 * @property-read array $other {&lt;br /&gt;
 *      Extra information about event.&lt;br /&gt;
 *&lt;br /&gt;
 *      - PUT INFO HERE&lt;br /&gt;
 * }&lt;br /&gt;
 *&lt;br /&gt;
 * @since     Moodle MOODLEVERSION&lt;br /&gt;
 * @copyright 2014 YOUR NAME&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 **/&lt;br /&gt;
class EVENTNAME extends \core\event\base {&lt;br /&gt;
    protected function init() {&lt;br /&gt;
        $this-&amp;gt;data[&#039;crud&#039;] = &#039;c&#039;; // c(reate), r(ead), u(pdate), d(elete)&lt;br /&gt;
        $this-&amp;gt;data[&#039;edulevel&#039;] = self::LEVEL_PARTICIPATING;&lt;br /&gt;
        $this-&amp;gt;data[&#039;objecttable&#039;] = &#039;...&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public static function get_name() {&lt;br /&gt;
        return get_string(&#039;eventEVENTNAME&#039;, &#039;FULLPLUGINNAME&#039;);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_description() {&lt;br /&gt;
        return &amp;quot;The user with id {$this-&amp;gt;userid} created ... ... ... with id {$this-&amp;gt;objectid}.&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_url() {&lt;br /&gt;
        return new \moodle_url(&#039;....&#039;, array(&#039;parameter&#039; =&amp;gt; &#039;value&#039;, ...));&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public function get_legacy_logdata() {&lt;br /&gt;
        // Override if you are migrating an add_to_log() call.&lt;br /&gt;
        return array($this-&amp;gt;courseid, &#039;PLUGINNAME&#039;, &#039;LOGACTION&#039;,&lt;br /&gt;
            &#039;...........&#039;,&lt;br /&gt;
            $this-&amp;gt;objectid, $this-&amp;gt;contextinstanceid);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    public static function get_legacy_eventname() {&lt;br /&gt;
        // Override ONLY if you are migrating events_trigger() call.&lt;br /&gt;
        return &#039;MYPLUGIN_OLD_EVENT_NAME&#039;;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    protected function get_legacy_eventdata() {&lt;br /&gt;
        // Override if you migrating events_trigger() call.&lt;br /&gt;
        $data = new \stdClass();&lt;br /&gt;
        $data-&amp;gt;id = $this-&amp;gt;objectid;&lt;br /&gt;
        $data-&amp;gt;userid = $this-&amp;gt;relateduserid;&lt;br /&gt;
        return $data;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Trigger the event instead of add_to_log() ===&lt;br /&gt;
&lt;br /&gt;
Replace the add_to_log() with an event trigger. The following is a common example of an event trigger inside an activity module.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
add_to_log($course-&amp;gt;id, &#039;PLUGINNAME&#039;, &#039;LOGACTION&#039;, &#039;...........&#039;, $objid, $cmid);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
...becomes...&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\EVENTNAME::create(array(&lt;br /&gt;
    &#039;objectid&#039; =&amp;gt; $objid,&lt;br /&gt;
    &#039;context&#039; =&amp;gt; context_module::instance($cmid)&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you need to trigger event multiple times in the code, or just prefer shorter syntax, you can declare your own static create function in the event class that would populate necessary fields and even add snapshots (see examples in mod_assign). In this case you can triger event in one line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
\FULLPLUGINNAME\event\EVENTNAME::create_from_someobject($someobject)-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 4. Increase the version number in version.php===&lt;br /&gt;
&lt;br /&gt;
The events that exist are only scanned when a plugin is installed or updated. Therefore when you change events, you need to increase the plugin&#039;s version number in its version.php to prompt an upgrade.&lt;br /&gt;
&lt;br /&gt;
== Replacing &#039;view&#039; events in modules ==&lt;br /&gt;
&lt;br /&gt;
Calls to add_to_log() to report a &#039;view&#039; event are usually found in mod/PLUGINNAME/view.php (or in a lib function included by this file) and indicate that a user viewed the module. &lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choosing the name ===&lt;br /&gt;
&lt;br /&gt;
Because this is a common event, the name is already chosen: &#039;&#039;&#039;course_module_viewed&#039;&#039;&#039; and the language string is defined in core.&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Defining class ===&lt;br /&gt;
&lt;br /&gt;
You must create a class for this event in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/course_module_viewed.php&#039;&#039;&#039; with the following format.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
class course_module_viewed extends \core\event\course_module_viewed {&lt;br /&gt;
    protected function init() {&lt;br /&gt;
        $this-&amp;gt;data[&#039;objecttable&#039;] = &#039;PLUGINNAME&#039;;&lt;br /&gt;
        parent::init();&lt;br /&gt;
    }&lt;br /&gt;
    // You might need to override get_url() and get_legacy_log_data() if view mode needs to be stored as well.&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Triggering the event ===&lt;br /&gt;
&lt;br /&gt;
This example takes data from $PAGE object but you may substitute this with ids and objects that you have fetched.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\course_module_viewed::create(array(&lt;br /&gt;
    &#039;objectid&#039; =&amp;gt; $PAGE-&amp;gt;cm-&amp;gt;instance,&lt;br /&gt;
    &#039;context&#039; =&amp;gt; $PAGE-&amp;gt;context,&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;add_record_snapshot(&#039;course&#039;, $PAGE-&amp;gt;course);&lt;br /&gt;
// In the next line you can use $PAGE-&amp;gt;activityrecord if you have set it, or skip this line if you don&#039;t have a record.&lt;br /&gt;
$event-&amp;gt;add_record_snapshot($PAGE-&amp;gt;cm-&amp;gt;modname, $activityrecord);&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Step 4. Update version.php===&lt;br /&gt;
Don&#039;t forget to update the plugin version number to prompt an upgrade.&lt;br /&gt;
&lt;br /&gt;
== Replacing &#039;view all&#039; events in modules ==&lt;br /&gt;
&lt;br /&gt;
Calls to add_to_log using &#039;view_all&#039; are usually found in mod/PLUGINNAME/index.php (or in a lib function included by this file). These invents indicate that a user viewed the list of all instances of this module within the course. &lt;br /&gt;
&lt;br /&gt;
=== Step 1. Choosing the name ===&lt;br /&gt;
&lt;br /&gt;
Because this is a common event, the name is already chosen: &#039;&#039;&#039;course_module_instance_list_viewed&#039;&#039;&#039; and the language string is defined in core.&lt;br /&gt;
&lt;br /&gt;
=== Step 2. Defining class ===&lt;br /&gt;
&lt;br /&gt;
You must create a class for this event in &#039;&#039;&#039;YOURPLUGINDIR/classes/event/course_module_instance_list_viewed.php&#039;&#039;&#039; with the following structure.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
namespace FULLPLUGINNAME\event;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
class course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed {&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Step 3. Triggering the event ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = \FULLPLUGINNAME\event\course_module_instance_list_viewed::create(array(&lt;br /&gt;
    &#039;context&#039; =&amp;gt; context_course::instance($course-&amp;gt;id)&lt;br /&gt;
));&lt;br /&gt;
$event-&amp;gt;trigger();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== What to include in the event ==&lt;br /&gt;
&lt;br /&gt;
=== init() and create() ===&lt;br /&gt;
&lt;br /&gt;
Ideally all information needed when initialising and triggering events should already be available without having to run additional queries. Queries run to fill event objects with data will cause additional performance load, which should be avoided. Information that needs to be gathered from the database should be provided by other event methods, which can be called selectively when needed.&lt;br /&gt;
&lt;br /&gt;
As you noticed in the examples above you can specify additional properties either by the overriding the init() method of the event or when calling create(). The first way is used for properties that are always the same for this event, the second is for dynamic properties that may differ when the event is triggered.&lt;br /&gt;
&lt;br /&gt;
Usually you need to include the following properties.&lt;br /&gt;
{| class=&amp;quot;nicetable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;context&#039;&#039;&#039; or &#039;&#039;&#039;contextid&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| Describes the context where the event took place.&lt;br /&gt;
| If you want to hardcode the system context, do so in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;crud&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| Describes whether the event reflects creation (c), reading (r), updating (u) or deleting (d). This should be a single character string.&lt;br /&gt;
| Most often are specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;edulevel&#039;&#039;&#039;&lt;br /&gt;
| required&lt;br /&gt;
| The level of educational value of the event. Can be LEVEL_TEACHING, LEVEL_PARTICIPATING or LEVEL_OTHER.&lt;br /&gt;
| Most often are specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;objecttable&#039;&#039;&#039; and &#039;&#039;&#039;objectid&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| Objecttable is the table that best represents the event object. Usually it is the object where the &amp;quot;CRUD&amp;quot; action was performed. This table is used by events that show the change in one record of one table, which will be the case for the most events.&lt;br /&gt;
| Since &#039;objecttable&#039; is always the same it is usually specified in init().&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;relateduserid&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| The id of the user affected by the event.&lt;br /&gt;
| Only used if it is easy to identify a single user who is affected by this operation. For example a user who is being graded, a user who receives the message, a user being enrolled, etc. &#039;&#039;&#039;This is NOT the user who performs the action&#039;&#039;&#039; (who is identified in the userid field).&lt;br /&gt;
|-&lt;br /&gt;
| &#039;&#039;&#039;other&#039;&#039;&#039;&lt;br /&gt;
| &lt;br /&gt;
| Everything else that you may think is important about this event. This property will be serialised and stored by loggers.&lt;br /&gt;
| Include only necessary information. It can be used in get_description(), get_url() and get_legacy_logdata(). This property should only contain an array or scalar value, it &#039;&#039;&#039;can not use objects&#039;&#039;&#039;.&lt;br /&gt;
Example of information stored in &#039;other&#039; can be found in event course_module_deleted:&lt;br /&gt;
* Definition: https://github.com/moodle/moodle/blob/MOODLE_27_STABLE/lib/classes/event/course_module_deleted.php#L71&lt;br /&gt;
* Triggering:https://github.com/moodle/moodle/blob/MOODLE_27_STABLE/course/lib.php#L1737..L1747&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Usually you don&#039;t need to include the following properties as they are deduced by the base class.&lt;br /&gt;
* &#039;userid&#039;: user who performs the action, taken from $USER&lt;br /&gt;
* &#039;courseid&#039;: course affected in the operation, which will be taken from context. It need not be specified at all for events that are not related to a particular course.&lt;br /&gt;
&lt;br /&gt;
See the [[Event_2#Information_contained_in_events|full list of properties]] for more information.&lt;br /&gt;
&lt;br /&gt;
=== get_legacy_logdata() ===&lt;br /&gt;
&lt;br /&gt;
This method is used to add log data to the legacy log. You need only override this method when replacing an add_to_log() call. Since this document is a transition guide from add_to_log() to events, you will most likely need to override this method. This method needs to return an array (with 3-7 elements) that imitates the arguments that used to be passed to the add_to_log() function. From Moodle 2.7, the get_legacy_logdata() method will only be called if legacy logging is enabled through the legacy logging plugin.&lt;br /&gt;
&lt;br /&gt;
=== get_description() and get_url() ===&lt;br /&gt;
&lt;br /&gt;
Most reporting tools will display aggregated event information (for example the count of student logins) so those methods, which describe individual events, are not likely to be called often; they will only be used by detailed reports such as loglive. At the moment, use get_description() to provide a very brief internal description of the action performed, so that it can be used for error recovery like any other system log. The description is hard-coded in English but it may be possible that future versions of Moodle (2.8 or later) will allow the use of translatable language strings. These methods should not make DB queries, access global variables, etc. For example, when a course is renamed or when a user is deleted, do not retrieve the course name or user name, instead simply use their ids. These functions should return exactly the same result whenever they are called, regardless of the environment or state, even after they have been restored from logs. &lt;br /&gt;
&lt;br /&gt;
=== get_legacy_eventname() and get_legacy_eventdata() ===&lt;br /&gt;
&lt;br /&gt;
You will need to override these two functions if you are upgrading events_trigger() calls. These will allow legacy plugins to continue to listen to your new events without upgrading their listeners.&lt;br /&gt;
&lt;br /&gt;
If you need to provide more detailed information to observers, you can choose to:&lt;br /&gt;
* add more information to &#039;other&#039;, but remember that this will be logged and it&#039;s better to keep logs as small as possible;&lt;br /&gt;
* use record snapshots, which are especially useful for delete actions (you can call get_record_snapshot() inside get_legacy_eventdata() and observers are encouraged to get data from snapshots as well);&lt;br /&gt;
* add new properties to your event class and define getter/setter functions, for example set_custom_data() and get_custom_data().&lt;br /&gt;
&lt;br /&gt;
=== add_record_snapshot() ===&lt;br /&gt;
&lt;br /&gt;
A record snapshot can be added for any DB table related to the event. If it is added, it must be an instance of stdClass containing all fields that are present in the corresponding DB table. You must add a record snapshot when you delete something from database. &#039;&#039;&#039;Record snapshots cannot be used from reports, it is intended for event observers only.&#039;&#039;&#039; Usually observers expect a record snapshot identified by &#039;objecttable&#039; and &#039;objectid&#039; but developers may also add snapshots of related tables, i.e. when book chapter is updated the developer may decide to add snapshots of related records in tables book_chapters, book, course_modules and course. &lt;br /&gt;
&lt;br /&gt;
Record snapshots should be added only when you already have an object and do not need to perform any additional DB queries to retrieve it. Otherwise omit it, as the record will be retrieved by get_record_snapshot() automatically, and only if needed. For performance reasons the snapshots are not guaranteed to contain an exact state at the time of event triggering, it may be fetched at any time between the triggering of event and its observation.&lt;br /&gt;
&lt;br /&gt;
== Events DON&#039;Ts ==&lt;br /&gt;
&lt;br /&gt;
Do not put more information in &#039;other&#039; than is needed. For example, do not include a full DB record for delete/create operations or a list of all changed properties in edit operations. If observers are interested in this information, it can requested by calling get_record_snapshot(). Never include large text fields in event data. &#039;&#039;&#039;Please help to keep the log size reasonable.&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Do NOT use $USER, $COURSE, $PAGE or other global variables when overriding get_* methods (with the exception of get_legacy_eventdata).&lt;br /&gt;
&lt;br /&gt;
Do NOT call $this-&amp;gt;get_record_snapshot() inside the event class (again with the exception of get_legacy_eventdata). If you need additional information for internal functions that cannot be added to existing properties, add it to the &#039;other&#039; property.&lt;br /&gt;
&lt;br /&gt;
Do NOT use $this-&amp;gt;context inside an event class. &#039;&#039;&#039;Remember that methods get_description() and get_url() may be called on events after they have been restored from logs.&#039;&#039;&#039; It is possible that the original context no longer exists when these functions are called. Instead use $this-&amp;gt;contextid, $this-&amp;gt;contextlevel, $this-&amp;gt;contextinstanceid.&lt;br /&gt;
&lt;br /&gt;
== Validation and testing ==&lt;br /&gt;
&lt;br /&gt;
You may notice that the most of events in Moodle also have function validate_data() . You can add this function for your own safety to ensure that you don&#039;t forget to define all required data when triggering event.&lt;br /&gt;
&lt;br /&gt;
Always use developer debugging mode when doing development. A lot of useful build-in validation will only work in development mode.&lt;br /&gt;
&lt;br /&gt;
We highly recommend to cover your events with unit tests. Search in standard plugins for files with the names events_test.php to see examples.&lt;br /&gt;
&lt;br /&gt;
In order to manually test the event you can perform the action and check how it appears in &#039;&#039;&#039;Course Administration &amp;gt; Reports &amp;gt; Logs&#039;&#039;&#039;. Also look up your event in the &#039;&#039;&#039;Site Administration &amp;gt; Reports &amp;gt; Events list&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== &amp;quot;Installation&amp;quot; of events ==&lt;br /&gt;
&lt;br /&gt;
Remember that you have to bump the plugin version in order to prompt an upgrade so that new events will be &amp;quot;installed&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
The [https://github.com/markn86/moodle-mod_certificate/pull/34 &#039;&#039;&#039;add_to_log deprecated, replace with events&#039;&#039;&#039;] issue on Github illustrates how the &#039;&#039;&#039;deprecated add_to_log()&#039;&#039;&#039; calls in the Certificate Module were upgraded to the new events method.&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Reports&amp;diff=44287</id>
		<title>Talk:Reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Reports&amp;diff=44287"/>
		<updated>2014-04-03T15:38:19Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /** Page and folder POSITION **/&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How your report gets included in the navigation==&lt;br /&gt;
This section says that &amp;quot;by default, your report will be included in the admin tree under the &#039;Reports&#039; section&amp;quot;. How does Moodle determine the POSITION of your report in that &#039;Reports&#039; section?&lt;br /&gt;
&lt;br /&gt;
And how can you force your report to appear in a specific position in that &#039;Reports&#039; folder, e.g. the top?&lt;br /&gt;
&lt;br /&gt;
You can use this code to create a FOLDER in which you can put your report(s):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$ADMIN-&amp;gt;add(&#039;reports&#039;, new admin_category(&#039;my_reports&#039;, get_string(&#039;my_reports&#039;,&#039;report_my_reports&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
but how do you force that folder to always appear at the top (or bottom) of the &#039;Reports&#039; folder?&lt;br /&gt;
&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 23:38, 3 April 2014 (WST)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Admin_reports&amp;diff=44286</id>
		<title>Talk:Admin reports</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Admin_reports&amp;diff=44286"/>
		<updated>2014-04-03T14:47:55Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /** Admin tree POSITION **/&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==How your report gets included in the admin tree==&lt;br /&gt;
This section says that &amp;quot;by default, your report will be included in the admin tree under the &#039;Reports&#039; section&amp;quot;. How does Moodle determine the POSITION of your report in that &#039;Reports&#039; section?&lt;br /&gt;
&lt;br /&gt;
And how can you force your report to appear in a specific position in that &#039;Reports&#039; folder, e.g. the top?&lt;br /&gt;
&lt;br /&gt;
You can use this code to create a FOLDER in which you can put your report(s):&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$ADMIN-&amp;gt;add(&#039;reports&#039;, new admin_category(&#039;my_reports&#039;, get_string(&#039;my_reports&#039;,&#039;report_my_reports&#039;)));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
but how do you force that folder to always appear at the top (or bottom) of the &#039;Reports&#039; folder?&lt;br /&gt;
&lt;br /&gt;
--[[User:Luis de Vasconcelos|Luis de Vasconcelos]] ([[User talk:Luis de Vasconcelos|talk]]) 22:47, 3 April 2014 (WST)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:lib/formslib.php_Form_Definition&amp;diff=43737</id>
		<title>Talk:lib/formslib.php Form Definition</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:lib/formslib.php_Form_Definition&amp;diff=43737"/>
		<updated>2014-02-07T12:39:04Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Dependent Dropdown Lists */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;There&#039;s items on here (e.g. &#039;duration&#039;) that are 2.0 only. Please can people adding them mark them as such to avoid confusion. Ta --[[User:Howard Miller|Howard Miller]] 11:42, 23 July 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
: Hi Howard, You can just add &amp;lt;nowiki&amp;gt;{{Moodle 2.0}}&amp;lt;/nowiki&amp;gt; to those items. I did that for &#039;duration&#039;. --[[User:Frank Ralf|Frank Ralf]] 11:54, 23 July 2009 (UTC)&lt;br /&gt;
&lt;br /&gt;
==No default value attribute for editor??==&lt;br /&gt;
tried the context key but doesn&#039;t work.&lt;br /&gt;
&lt;br /&gt;
== Use Static elements with care? ==&lt;br /&gt;
&lt;br /&gt;
Why are static elements listed as being used with care?&lt;br /&gt;
&lt;br /&gt;
== &#039;&#039;Please do not create conditional elements in definition(), the definition() should not directly depend on the submitted data.&#039;&#039; ==&lt;br /&gt;
&lt;br /&gt;
I&#039;m really not sure what this means. Does it actually mean &amp;quot;do not create elements that are conditional upon the values of other submitted elements&amp;quot; as opposed to not creating conditional elements at all? Lots of forms have conditional elements --[[User:Howard Miller|Howard Miller]] 13:06, 6 February 2011 (UTC)&lt;br /&gt;
&lt;br /&gt;
Yes, it means don&#039;t create things that are conditional on the data that the form will be editing. It is OK to condition on admin settings (e.g. if conditional activities are turned off, those options do not appear on the mod_edit forms. Or, perhaps, on capabilities. However, in that case you have to be careful. If someone without the capability uses the form, you have to make sure that when they submit, you don&#039;t overwrite the correct value in the database with blank from the form. In that situation, it may be better to use hardFreeze on those form elements, instead of conditionally omitting them.--[[User:Tim Hunt|Tim Hunt]] 15:14, 6 February 2011 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Very disappointing, that nested fieldsets are not supported :( ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&amp;quot;$mform-&amp;gt;addElement(&#039;header&#039;, &#039;nameforyourheaderelement&#039;, get_string(&#039;titleforlegened&#039;, &#039;modulename&#039;));&#039;&#039;&lt;br /&gt;
&#039;&#039;You can&#039;t yet nest these visible fieldsets unfortunately. But in fact groups of elements are wrapped in invisible fieldsets.&#039;&#039;&lt;br /&gt;
&#039;&#039;You close a fieldset with moodle_form&#039;s closeHeaderBefore method. You tell closeHeaderBefore the element before you wish to end the fieldset. A fieldset is automatically closed if you open a new one.&amp;quot;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Should be possible to nest fieldsets!&#039;&#039;&#039;&lt;br /&gt;
&#039;&#039;&#039;Please add this feature!&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;As I know this feature was already added to QuickForms.&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
&#039;&#039;&#039;See example QuickForm solution of nested fieldset here:&#039;&#039;&#039;&amp;lt;br&amp;gt;&lt;br /&gt;
[http://pear.saltybeagle.com/HTML_QuickForm_Renderer_Tableless/stack.php http://pear.saltybeagle.com/HTML_QuickForm_Renderer_Tableless/stack.php]&amp;lt;br&amp;gt;&lt;br /&gt;
Konrad Lorinczi [[User:- -|- -]] 18:02, 23 March 2011 (UTC)&lt;br /&gt;
&lt;br /&gt;
== Multiple file uploads? ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If one has multiple files to be uploaded using the form and all files are to go in different location. It feels like, the below code does not satisfy the needs to do anything of this sort.&lt;br /&gt;
------------------------------------------&lt;br /&gt;
after form submission and validation use&lt;br /&gt;
&lt;br /&gt;
if ($data = $mform-&amp;gt;get_data()) {&lt;br /&gt;
      ...&lt;br /&gt;
    $mform-&amp;gt;save_files($destination_directory);&lt;br /&gt;
      ...&lt;br /&gt;
}&lt;br /&gt;
--------------------------------------------&lt;br /&gt;
How this can be done?&lt;br /&gt;
Thanks.&lt;br /&gt;
&lt;br /&gt;
==Dependent Dropdown Lists==&lt;br /&gt;
&lt;br /&gt;
Does Formslib support adding dependent dropdown lists to a form? This is where the options that are displayed on list2 are dependent on the option that is selected on list1.&lt;br /&gt;
The [https://moodle.org/mod/forum/discuss.php?d=163019 how to implement dependent dropdown lists] discussion on the Using Moodle forum talks about something similar and offers a &amp;quot;hacky&amp;quot; approach. But that was in 2010. Can this be easily done in Moodle 2.5/2.6?&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:YUI&amp;diff=43344</id>
		<title>Talk:YUI</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:YUI&amp;diff=43344"/>
		<updated>2013-12-03T16:26:39Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: Applicable versions&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Applicable Version==&lt;br /&gt;
Does this page only apply to Moodle version 2.0, like the {Moodle 2.0} label implies? Or is this still relevant to the current versions of Moodle (2.5/2.6)?&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Windows_Installer&amp;diff=42066</id>
		<title>Windows Installer</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Windows_Installer&amp;diff=42066"/>
		<updated>2013-08-14T13:10:47Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Resources: fix 404 link */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Windows Installer Package ==&lt;br /&gt;
The Windows Installer is based on xampp 1.6 distribution. The package structure is the following:&lt;br /&gt;
&lt;br /&gt;
   Root&lt;br /&gt;
   | &#039;&#039;&#039;Readme.txt&#039;&#039;&#039;&lt;br /&gt;
   | &#039;&#039;&#039;Start Moodle.exe&#039;&#039;&#039;&lt;br /&gt;
   | &#039;&#039;&#039;Stop Moodle.exe&#039;&#039;&#039;&lt;br /&gt;
   | server&lt;br /&gt;
     | apache_start.bat&lt;br /&gt;
     | apache_stop.bat&lt;br /&gt;
     | makecert.bat&lt;br /&gt;
     | mysql_start.bat&lt;br /&gt;
     | mysql_stop.bat&lt;br /&gt;
     | readme_de.txt&lt;br /&gt;
     | readme_en.txt&lt;br /&gt;
     | service.exe&lt;br /&gt;
     | setup_xampp.bat&lt;br /&gt;
     | xampp_restart.bat&lt;br /&gt;
     | xampp_start.exe&lt;br /&gt;
     | xampp_stop.exe&lt;br /&gt;
     | xampp_control.exe&lt;br /&gt;
     | xampp_portcheck.exe&lt;br /&gt;
     | apache&lt;br /&gt;
     | cgi-bin&lt;br /&gt;
     | install&lt;br /&gt;
     | licences&lt;br /&gt;
     | &#039;&#039;&#039;moodle&#039;&#039;&#039;&lt;br /&gt;
     | &#039;&#039;&#039;moodledata&#039;&#039;&#039; &#039;&#039;//this folder is created during the installation process&#039;&#039;&lt;br /&gt;
     | mysql&lt;br /&gt;
     | php&lt;br /&gt;
     | sendmail&lt;br /&gt;
     | tmp&lt;br /&gt;
&lt;br /&gt;
== Moodle folders ==&lt;br /&gt;
All moodle files must be located in server/moodle/&lt;br /&gt;
&lt;br /&gt;
== &#039;Start/Stop Moodle.exe&#039; ==&lt;br /&gt;
Windows Installer package comes with two executable files. &#039;Start Moodle.exe&#039; sets up the Xampp environment and launch Apache and Mysql processes. &#039;Stop Moodle.exe&#039; stop the two processes. This section explains how to create these two executable files.&lt;br /&gt;
&lt;br /&gt;
=== 1. Create a batch file ===&lt;br /&gt;
The two batch files can be download on CVS: http://cvs.moodle.org/contrib/tools/m4w_builder/bin/batch/&lt;br /&gt;
==== &#039;Start Moodle.exe&#039; ====&lt;br /&gt;
This batch file readjusts, if needed, apache/mysql paths to the new location in hard disk. (server/setup_xampp.bat)&lt;br /&gt;
Then it launchs Apache and Mysql processes. (server/xampp_start.exe)&lt;br /&gt;
&lt;br /&gt;
==== &#039;Stop Moodle.exe&#039; ====&lt;br /&gt;
This batch file stops the apache and mysql process. (server/xampp_start.exe)&lt;br /&gt;
&lt;br /&gt;
=== 2. Create an icon ===&lt;br /&gt;
In order to create an icon for an executable file you can use SnIco Edit. You need to save your icon as a .ico file.&lt;br /&gt;
&lt;br /&gt;
=== 3. Create an executable file ===&lt;br /&gt;
Once you&#039;ve got a batch file and an icon file, run bat_to_exe_converter.exe. Browse for the .bat file and the .ico file, then click on Compile. An executable file is generated. &lt;br /&gt;
The two generated files (and a Readme.txt) need to be copied into the Windows Installer zip at the root level. This is done by a script shell generating the windows installer package.&lt;br /&gt;
&lt;br /&gt;
== Resources ==&lt;br /&gt;
You can find all resources in CVS: http://cvs.moodle.org/contrib/tools/m4w_builder/bin/&lt;br /&gt;
&lt;br /&gt;
* [http://www.apachefriends.org/en/xampp.html Xampp]: the WAMP distribution used in the Windows Installer package. &lt;br /&gt;
* [http://www.snidesoft.eu SnIco Edit]: create/edit your .ico icon file.&lt;br /&gt;
* [http://www.f2ko.de/programs.php?lang=en&amp;amp;pid=b2e Bat to Exe Converter]: convert a .bat file into a .exe file.&lt;br /&gt;
* [http://www.jrsoftware.org/isinfo.php Inno Setup]: create a Windows Installer software. (setup.exe)&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Talk:Developer_meeting_July_2013&amp;diff=41649</id>
		<title>Talk:Developer meeting July 2013</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Talk:Developer_meeting_July_2013&amp;diff=41649"/>
		<updated>2013-07-30T09:55:05Z</updated>

		<summary type="html">&lt;p&gt;Libertymoodle: /* Dev Chat */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==Dev Chat==&lt;br /&gt;
Who has access to the [https://moodle.org/local/chatlogs/info.php &amp;quot;Regular Dev chat&amp;quot;]? I get a &amp;quot;Sorry, but you do not currently have permissions to do that (View chat logs)&amp;quot; message when I go there.&lt;/div&gt;</summary>
		<author><name>Libertymoodle</name></author>
	</entry>
</feed>