<?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=Markn</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=Markn"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Markn"/>
	<updated>2026-04-26T07:27:26Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Graderule_API&amp;diff=60521</id>
		<title>Graderule API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Graderule_API&amp;diff=60521"/>
		<updated>2021-07-29T11:53:51Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Graderule&lt;br /&gt;
|state = In development&lt;br /&gt;
|tracker = MDL-60155&lt;br /&gt;
|discussion =&lt;br /&gt;
|assignee = Mark Nelson&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 4.0}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
A grade rule plugin is a plugin that allows you to manipulate users final grades in the gradebook based on business rules.&lt;br /&gt;
&lt;br /&gt;
=== History ===&lt;br /&gt;
&lt;br /&gt;
This work was borne primarily as a way for Monash University to be able to implement hurdles functionality. A hurdle in their nomenclature being a grade item (or activity) that a student has to pass in order to pass the entire course. Having conditional calculations were only about half the solution as they required for a specific maximum mark and grade letter if a student failed a hurdle.&lt;br /&gt;
&lt;br /&gt;
== Anatomy of a Grade Rule Plugin ==&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Graderule_API&amp;diff=60520</id>
		<title>Graderule API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Graderule_API&amp;diff=60520"/>
		<updated>2021-07-29T11:53:09Z</updated>

		<summary type="html">&lt;p&gt;Markn: Created page with &amp;quot;{{Infobox Project |name = Graderule |state = In development |tracker = MDL-60155 |discussion = |assignee = Marcus Boon }} {{Moodle 3.9}} == Introduction ==  A grade rule plugi...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Infobox Project&lt;br /&gt;
|name = Graderule&lt;br /&gt;
|state = In development&lt;br /&gt;
|tracker = MDL-60155&lt;br /&gt;
|discussion =&lt;br /&gt;
|assignee = Marcus Boon&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 3.9}}&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
A grade rule plugin is a plugin that allows you to manipulate users final grades in the gradebook based on business rules.&lt;br /&gt;
&lt;br /&gt;
=== History ===&lt;br /&gt;
&lt;br /&gt;
This work was borne primarily as a way for Monash University to be able to implement hurdles functionality. A hurdle in their nomenclature being a grade item (or activity) that a student has to pass in order to pass the entire course. Having conditional calculations were only about half the solution as they required for a specific maximum mark and grade letter if a student failed a hurdle.&lt;br /&gt;
&lt;br /&gt;
== Anatomy of a Grade Rule Plugin ==&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53023</id>
		<title>Tag API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53023"/>
		<updated>2017-10-13T03:57:11Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Deleting and clearing tags */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.1}}&lt;br /&gt;
&lt;br /&gt;
==Tag API overview==&lt;br /&gt;
&lt;br /&gt;
The Tag API allows you to assign labels to information in Moodle. This makes finding this information easier and also facilitates the grouping of similar information. The Tag API allows you to create, modify, delete and search tags in the Moodle system. The main tag related functions can be found in the tag/classes/tag.php file. For a through overview of all of the functions available for working with Tags please see methods in core_tag_tag, core_tag_collection and core_tag_area classes, however the following examples should give you a general understanding of how to get started with tags.&lt;br /&gt;
&lt;br /&gt;
This page describes API in Moodle 3.1 and above, for earlier versions see [[Tag API before 3.1]]&lt;br /&gt;
&lt;br /&gt;
==Tag API usage==&lt;br /&gt;
&lt;br /&gt;
When user tags something a &#039;&#039;&#039;tag instance&#039;&#039;&#039; is created in the database linking the item to the actual &#039;&#039;&#039;tag&#039;&#039;&#039;. If tag did not exist before it is created automatically. Do not confuse these two entities - deleting the tag instance does not normally delete tag, however deleting tag deletes all tag instances associated with it. &lt;br /&gt;
&lt;br /&gt;
Developers define &#039;&#039;&#039;tag areas&#039;&#039;&#039; the areas that can be tagged, examples are:&lt;br /&gt;
* blog posts&lt;br /&gt;
* courses&lt;br /&gt;
* users (tags represent user interests)&lt;br /&gt;
* activity modules&lt;br /&gt;
* questions&lt;br /&gt;
* wiki pages&lt;br /&gt;
&lt;br /&gt;
Each tag area is identified by two attributes - component and itemtype. &#039;&#039;Itemtype must be a name of a table in the database.&#039;&#039; Component is the core component or plugin responsible for the tagging. This way the same DB table (for example &#039;user&#039; or &#039;course&#039;) may be independently tagged by several components. Administrator or manager is able to manage the tag areas, collections and tags inside them on the [https://docs.moodle.org/en/Managing_tags Managing tags] page. Users are able to search tags and view all items tagged with them that they have access to.&lt;br /&gt;
&lt;br /&gt;
===Defining a tag area===&lt;br /&gt;
&lt;br /&gt;
First, developer must define the tag areas in the file &#039;&#039;&#039;db/tag.php&#039;&#039;&#039;. This will usually look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$tagareas = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;,  // This must be a name of the database table (without prefix).&lt;br /&gt;
        &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;, // This can be omitted for plugins since it can only be full frankenstyle name of the plugin.&lt;br /&gt;
        &#039;callback&#039; =&amp;gt; &#039;mod_wiki_get_tagged_pages&#039;,&lt;br /&gt;
        &#039;callbackfile&#039; =&amp;gt; &#039;/mod/wiki/locallib.php&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
You will also need to add language string, for the example above it will be &#039;&#039;&#039;$string[&#039;tagarea_wiki_pages&#039;] = &#039;Wiki pages&#039;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There are more options such as specifying the default value for &amp;quot;Standard tags&amp;quot;, having a fixed collection or excluding from search. They can be found in comments in [[https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]]&lt;br /&gt;
&lt;br /&gt;
After making changes to db/tag.php plugin developer must bump the plugin version in &#039;&#039;&#039;version.php&#039;&#039;&#039; and run upgrade script. This usually applies to any changes in the db/ folder.&lt;br /&gt;
&lt;br /&gt;
===Adding tags element to the editing form===&lt;br /&gt;
&lt;br /&gt;
After tag area is defined it should appear on &amp;quot;Manage tags&amp;quot; page. Now it is time to allow users to add/change tags when editing the item. Here is an example from Wiki module:&lt;br /&gt;
&lt;br /&gt;
1. Add a &#039;tags&#039; form element to the editing form:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;tags&#039;, get_string(&#039;tags&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;, &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This element will automatically check if the tag area is disabled by the manager and will not display anything in this case. However if you want to add a header you need to check if tag area is enabled add this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (core_tag_tag::is_enabled(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;)) {&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;header&#039;, &#039;tagshdr&#039;, get_string(&#039;tags&#039;, &#039;tag&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Save the form data&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $form-&amp;gt;get_data()) {&lt;br /&gt;
    // Do some other processing here, if this is a new page (item) you need to insert it in the DB and obtain id.&lt;br /&gt;
    // $pageid = $data-&amp;gt;id;&lt;br /&gt;
    core_tag_tag::set_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $pageid, $modulecontext, $data-&amp;gt;tags);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
It is important to specify the correct context in this function. Note that $data-&amp;gt;tags will always be returned by the form, even if the area is disabled, however core_tag_tag::set_item_tags() will not change or reset tags if the tag area is disabled.&lt;br /&gt;
&lt;br /&gt;
3. Populate the form with existing tags before calling $form-&amp;gt;set_data($data):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$data = $DB-&amp;gt;get_record(&#039;wiki_pages&#039;, array(&#039;id&#039; =&amp;gt; $this-&amp;gt;page-&amp;gt;id)); // Well, it&#039;s more complicated than that of course....&lt;br /&gt;
$data-&amp;gt;tags = core_tag_tag::get_item_tags_array(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $this-&amp;gt;page-&amp;gt;id);&lt;br /&gt;
$form-&amp;gt;set_data($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Always test the code with tag area enabled and disabled.&lt;br /&gt;
&lt;br /&gt;
===Displaying tags next to the item===&lt;br /&gt;
&lt;br /&gt;
Example of displaying of the tags are user interests on the user profile page. User can see the list of interests, each of them is a link that leads to the page that shows all items tagged with this tag.&lt;br /&gt;
&lt;br /&gt;
Here is the code used by Wiki module to display tags the page is tagged with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;tag_list(core_tag_tag::get_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $page-&amp;gt;id), null, &#039;wiki-tags&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting and clearing tags===&lt;br /&gt;
&lt;br /&gt;
Cron will automatically remove tag instances that point to non existing items, however it is a good habit to delete tags when the record is deleted.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please note:&#039;&#039;&#039; If you have created a course activity that uses tags you should also remember to delete the tags during a course reset by adding code to the reset course callbacks. First you want to add a checkbox that a user can check if they wish to delete the tags, then code that handles the case when the checkbox has been checked. Example -&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * The elements to add the course reset form.&lt;br /&gt;
 *&lt;br /&gt;
 * @param moodleform $mform&lt;br /&gt;
 */&lt;br /&gt;
function book_reset_course_form_definition(&amp;amp;$mform) {&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;header&#039;, &#039;bookheader&#039;, get_string(&#039;modulenameplural&#039;, &#039;book&#039;));&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;reset_book_tags&#039;, get_string(&#039;removeallbooktags&#039;, &#039;book&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This function is used by the reset_course_userdata function in moodlelib.&lt;br /&gt;
 * @param $data the data submitted from the reset course.&lt;br /&gt;
 * @return array status array&lt;br /&gt;
 */&lt;br /&gt;
function book_reset_userdata($data) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
&lt;br /&gt;
    $status = [];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($data-&amp;gt;reset_book_tags)) {&lt;br /&gt;
        // Loop through the books and remove the tags from the chapters.&lt;br /&gt;
        if ($books = $DB-&amp;gt;get_records(&#039;book&#039;, array(&#039;course&#039; =&amp;gt; $data-&amp;gt;courseid))) {&lt;br /&gt;
            foreach ($books as $book) {&lt;br /&gt;
                if (!$cm = get_coursemodule_from_instance(&#039;book&#039;, $book-&amp;gt;id)) {&lt;br /&gt;
                    continue;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
                core_tag_tag::delete_instances(&#039;mod_book&#039;, null, $context-&amp;gt;id);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $status[] = [&lt;br /&gt;
            &#039;component&#039; =&amp;gt; get_string(&#039;modulenameplural&#039;, &#039;book&#039;),&lt;br /&gt;
            &#039;item&#039; =&amp;gt; get_string(&#039;tagsdeleted&#039;, &#039;book&#039;),&lt;br /&gt;
            &#039;error&#039; =&amp;gt; false&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return $status;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The functions used to delete the tags are -&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
core_tag_tag::remove_all_item_tags($component, $itemtype, $itemid, $tiuserid = 0) // Removes all tag instances associated with an item.&lt;br /&gt;
core_tag_tag::delete_instances($component, $itemtype = null, $contextid = null) // Removes tag instances in bulk. Here $component is mandatory in this method, either itemtype or contextid or neither or both can be specified.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Backup and restore===&lt;br /&gt;
&lt;br /&gt;
When you tag contents inside the course the plugin has to hook into backup and restore and process necessary tags. This is especially important for the contents inside activity modules, such as wiki pages or forum posts. Questions in the course question bank also backup and restore their tags.&lt;br /&gt;
&lt;br /&gt;
You can choose to backup and restore tags for each item individually (as it is done in mod_wiki) OR backup all tags in the context at once (as it is done in mod_glossary or mod_forum). Second option is preferable for performance reasons. Make sure to take into account $userinfo (whether user information is backed up / restored), for example wiki pages is not user information but glossary entries are, tags on them follow the same rule.&lt;br /&gt;
&lt;br /&gt;
This is an example from Glossary module that can be found in &#039;&#039;&#039;backup_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    $tags = new backup_nested_element(&#039;entriestags&#039;);&lt;br /&gt;
    $tag = new backup_nested_element(&#039;tag&#039;, array(&#039;id&#039;), array(&#039;itemid&#039;, &#039;rawname&#039;));&lt;br /&gt;
    // ...&lt;br /&gt;
    $glossary-&amp;gt;add_child($tags); // Note that parent node is the glossary, not glossary entry, however the individual entries are tagged.&lt;br /&gt;
    $tags-&amp;gt;add_child($tag);&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo &amp;amp;&amp;amp; core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) {&lt;br /&gt;
        $tag-&amp;gt;set_source_sql(&#039;SELECT t.id, ti.itemid, t.rawname&lt;br /&gt;
                                FROM {tag} t&lt;br /&gt;
                                JOIN {tag_instance} ti ON ti.tagid = t.id&lt;br /&gt;
                               WHERE ti.itemtype = ?&lt;br /&gt;
                                 AND ti.component = ?&lt;br /&gt;
                                 AND ti.contextid = ?&#039;, array(&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;glossary_entries&#039;),&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;mod_glossary&#039;),&lt;br /&gt;
            backup::VAR_CONTEXTID));&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And this in the &#039;&#039;&#039;restore_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo) {&lt;br /&gt;
        $paths[] = new restore_path_element(&#039;glossary_entry_tag&#039;, &#039;/activity/glossary/entriestags/tag&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
protected function process_glossary_entry_tag($data) {&lt;br /&gt;
    $data = (object)$data;&lt;br /&gt;
&lt;br /&gt;
    if (!core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) { // Tags disabled on this site, nothing to process.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $tag = $data-&amp;gt;rawname;&lt;br /&gt;
    if (!$itemid = $this-&amp;gt;get_mappingid(&#039;glossary_entry&#039;, $data-&amp;gt;itemid)) {&lt;br /&gt;
        // Orphaned tag, we could not find the glossary entry for it - ignore.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $context = context_module::instance($this-&amp;gt;task-&amp;gt;get_moduleid());&lt;br /&gt;
    core_tag_tag::add_item_tag(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;, $itemid, $context, $tag);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Search callback===&lt;br /&gt;
&lt;br /&gt;
This is the most difficult part of Tag API. When user searches for the items tagged with a specific tag only the items user has access to must be returned. Running access check on all items can be very costly. Class &#039;&#039;&#039;core_tag_index_builder&#039;&#039;&#039; can help with retrieving and caching records, especially inside the courses or activity modules.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_wiki_get_tagged_pages($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = 1, $page = 0) {&lt;br /&gt;
    // Find items.&lt;br /&gt;
    // Please refer to existing callbacks in core for examples.&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    // Use core_tag_index_builder to build and filter the list of items. &lt;br /&gt;
    // Notice how we search for 6 items when we need to display 5 - this way we will know that we need to display a link to the next page.&lt;br /&gt;
    $builder = new core_tag_index_builder(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $query, $params, $page * $perpage, $perpage + 1);&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    $items = $builder-&amp;gt;get_items();&lt;br /&gt;
    if (count($items) &amp;gt; $perpage) {&lt;br /&gt;
        $totalpages = $page + 2; // We don&#039;t need exact page count, just indicate that the next page exists.&lt;br /&gt;
        array_pop($items);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Build the display contents.&lt;br /&gt;
    if ($items) {&lt;br /&gt;
        $tagfeed = new core_tag\output\tagfeed();&lt;br /&gt;
        foreach ($items as $item) {&lt;br /&gt;
            $tagfeed-&amp;gt;add(...);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $content = $OUTPUT-&amp;gt;render_from_template(&#039;core_tag/tagfeed&#039;, $tagfeed-&amp;gt;export_for_template($OUTPUT));&lt;br /&gt;
&lt;br /&gt;
        return new core_tag\output\tagindex($tag, &#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $content,&lt;br /&gt;
                $exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===User-specific tags===&lt;br /&gt;
&lt;br /&gt;
It is possible that each tagged item can be tagged by each user independently. Before Moodle 3.0 this was how courses were tagged however from 3.0 tagging courses became more standard. The functionality remains in the API (argument $tiuser to the tagging functions).  In this case both tag list and tag cloud will display all tag instances added by all users but each user will be able to edit only their own.&lt;br /&gt;
&lt;br /&gt;
If developer chooses to implement it in the plugin, they need to also implement the UI when admin or other privileged user can remove or edit the instances of another user. Otherwise if teacher has tagged the course and later resigned there will be no way to change their tags. Also such tag instances need special treatment during backup and restore - they are now considered &amp;quot;user data&amp;quot; and user id mapping should be performed.&lt;br /&gt;
&lt;br /&gt;
===Advanced usages===&lt;br /&gt;
&lt;br /&gt;
Custom plugins may go beyond the standard tags handling and use them without mixing with regular course/user/wiki/blogs tags, hide them from the &amp;quot;Tag search&amp;quot; page and &amp;quot;Tags&amp;quot; block but instead have their own interface to search/categorise using tags. This can be achieved by defining tag collection, make it not searchable and specify a custom URL to link to when the tag is actually displayed. This all can be defined in db/tag.php, see the comments in [https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tag_area::get_collection($component, $itemtype)&#039;&#039;&#039; - will return you the collection that your tag area is in&lt;br /&gt;
* &#039;&#039;&#039;tag_collection::get_tag_cloud()&#039;&#039;&#039; - will return all tags in the collection. There are no API methods to get the tags used in the tag area - this is actually the purpose of tag collections.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[Tag API before 3.1]]&lt;br /&gt;
* [https://docs.moodle.org/en/Managing_tags Managing tags]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53005</id>
		<title>Tag API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53005"/>
		<updated>2017-10-12T11:13:24Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Deleting and clearing tags */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.1}}&lt;br /&gt;
&lt;br /&gt;
==Tag API overview==&lt;br /&gt;
&lt;br /&gt;
The Tag API allows you to assign labels to information in Moodle. This makes finding this information easier and also facilitates the grouping of similar information. The Tag API allows you to create, modify, delete and search tags in the Moodle system. The main tag related functions can be found in the tag/classes/tag.php file. For a through overview of all of the functions available for working with Tags please see methods in core_tag_tag, core_tag_collection and core_tag_area classes, however the following examples should give you a general understanding of how to get started with tags.&lt;br /&gt;
&lt;br /&gt;
This page describes API in Moodle 3.1 and above, for earlier versions see [[Tag API before 3.1]]&lt;br /&gt;
&lt;br /&gt;
==Tag API usage==&lt;br /&gt;
&lt;br /&gt;
When user tags something a &#039;&#039;&#039;tag instance&#039;&#039;&#039; is created in the database linking the item to the actual &#039;&#039;&#039;tag&#039;&#039;&#039;. If tag did not exist before it is created automatically. Do not confuse these two entities - deleting the tag instance does not normally delete tag, however deleting tag deletes all tag instances associated with it. &lt;br /&gt;
&lt;br /&gt;
Developers define &#039;&#039;&#039;tag areas&#039;&#039;&#039; the areas that can be tagged, examples are:&lt;br /&gt;
* blog posts&lt;br /&gt;
* courses&lt;br /&gt;
* users (tags represent user interests)&lt;br /&gt;
* activity modules&lt;br /&gt;
* questions&lt;br /&gt;
* wiki pages&lt;br /&gt;
&lt;br /&gt;
Each tag area is identified by two attributes - component and itemtype. &#039;&#039;Itemtype must be a name of a table in the database.&#039;&#039; Component is the core component or plugin responsible for the tagging. This way the same DB table (for example &#039;user&#039; or &#039;course&#039;) may be independently tagged by several components. Administrator or manager is able to manage the tag areas, collections and tags inside them on the [https://docs.moodle.org/en/Managing_tags Managing tags] page. Users are able to search tags and view all items tagged with them that they have access to.&lt;br /&gt;
&lt;br /&gt;
===Defining a tag area===&lt;br /&gt;
&lt;br /&gt;
First, developer must define the tag areas in the file &#039;&#039;&#039;db/tag.php&#039;&#039;&#039;. This will usually look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$tagareas = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;,  // This must be a name of the database table (without prefix).&lt;br /&gt;
        &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;, // This can be omitted for plugins since it can only be full frankenstyle name of the plugin.&lt;br /&gt;
        &#039;callback&#039; =&amp;gt; &#039;mod_wiki_get_tagged_pages&#039;,&lt;br /&gt;
        &#039;callbackfile&#039; =&amp;gt; &#039;/mod/wiki/locallib.php&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
You will also need to add language string, for the example above it will be &#039;&#039;&#039;$string[&#039;tagarea_wiki_pages&#039;] = &#039;Wiki pages&#039;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There are more options such as specifying the default value for &amp;quot;Standard tags&amp;quot;, having a fixed collection or excluding from search. They can be found in comments in [[https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]]&lt;br /&gt;
&lt;br /&gt;
After making changes to db/tag.php plugin developer must bump the plugin version in &#039;&#039;&#039;version.php&#039;&#039;&#039; and run upgrade script. This usually applies to any changes in the db/ folder.&lt;br /&gt;
&lt;br /&gt;
===Adding tags element to the editing form===&lt;br /&gt;
&lt;br /&gt;
After tag area is defined it should appear on &amp;quot;Manage tags&amp;quot; page. Now it is time to allow users to add/change tags when editing the item. Here is an example from Wiki module:&lt;br /&gt;
&lt;br /&gt;
1. Add a &#039;tags&#039; form element to the editing form:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;tags&#039;, get_string(&#039;tags&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;, &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This element will automatically check if the tag area is disabled by the manager and will not display anything in this case. However if you want to add a header you need to check if tag area is enabled add this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (core_tag_tag::is_enabled(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;)) {&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;header&#039;, &#039;tagshdr&#039;, get_string(&#039;tags&#039;, &#039;tag&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Save the form data&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $form-&amp;gt;get_data()) {&lt;br /&gt;
    // Do some other processing here, if this is a new page (item) you need to insert it in the DB and obtain id.&lt;br /&gt;
    // $pageid = $data-&amp;gt;id;&lt;br /&gt;
    core_tag_tag::set_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $pageid, $modulecontext, $data-&amp;gt;tags);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
It is important to specify the correct context in this function. Note that $data-&amp;gt;tags will always be returned by the form, even if the area is disabled, however core_tag_tag::set_item_tags() will not change or reset tags if the tag area is disabled.&lt;br /&gt;
&lt;br /&gt;
3. Populate the form with existing tags before calling $form-&amp;gt;set_data($data):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$data = $DB-&amp;gt;get_record(&#039;wiki_pages&#039;, array(&#039;id&#039; =&amp;gt; $this-&amp;gt;page-&amp;gt;id)); // Well, it&#039;s more complicated than that of course....&lt;br /&gt;
$data-&amp;gt;tags = core_tag_tag::get_item_tags_array(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $this-&amp;gt;page-&amp;gt;id);&lt;br /&gt;
$form-&amp;gt;set_data($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Always test the code with tag area enabled and disabled.&lt;br /&gt;
&lt;br /&gt;
===Displaying tags next to the item===&lt;br /&gt;
&lt;br /&gt;
Example of displaying of the tags are user interests on the user profile page. User can see the list of interests, each of them is a link that leads to the page that shows all items tagged with this tag.&lt;br /&gt;
&lt;br /&gt;
Here is the code used by Wiki module to display tags the page is tagged with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;tag_list(core_tag_tag::get_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $page-&amp;gt;id), null, &#039;wiki-tags&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting and clearing tags===&lt;br /&gt;
&lt;br /&gt;
Cron will automatically remove tag instances that point to non existing items, however it is a good habit to delete tags when the record is deleted.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Please note:&#039;&#039;&#039; If you have created a course activity that uses tags you should also remember to delete the tags during a course reset by adding code to the reset course callbacks. First you want to add a checkbox that a user can check if they wish to delete the tags, then code that handles the case when the checkbox has been checked. Example -&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * The elements to add the course reset form.&lt;br /&gt;
 *&lt;br /&gt;
 * @param moodleform $mform&lt;br /&gt;
 */&lt;br /&gt;
function book_reset_course_form_definition(&amp;amp;$mform) {&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;header&#039;, &#039;bookheader&#039;, get_string(&#039;modulenameplural&#039;, &#039;book&#039;));&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;checkbox&#039;, &#039;reset_book_tags&#039;, get_string(&#039;removeallbooktags&#039;, &#039;book&#039;));&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * This function is used by the reset_course_userdata function in moodlelib.&lt;br /&gt;
 * @param $data the data submitted from the reset course.&lt;br /&gt;
 * @return array status array&lt;br /&gt;
 */&lt;br /&gt;
function book_reset_userdata($data) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
&lt;br /&gt;
    $status = [];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($data-&amp;gt;reset_book_tags)) {&lt;br /&gt;
        // Loop through the books and remove the tags from the chapters.&lt;br /&gt;
        if ($books = $DB-&amp;gt;get_records(&#039;book&#039;, array(&#039;course&#039; =&amp;gt; $data-&amp;gt;courseid))) {&lt;br /&gt;
            foreach ($books as $book) {&lt;br /&gt;
                if (!$cm = get_coursemodule_from_instance(&#039;book&#039;, $book-&amp;gt;id)) {&lt;br /&gt;
                    continue;&lt;br /&gt;
                }&lt;br /&gt;
&lt;br /&gt;
                $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
                core_tag_tag::delete_instances(&#039;mod_book&#039;, null, $context-&amp;gt;id);&lt;br /&gt;
            }&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $status[] = [&lt;br /&gt;
            &#039;component&#039; =&amp;gt; get_string(&#039;modulenameplural&#039;, &#039;book&#039;),&lt;br /&gt;
            &#039;item&#039; =&amp;gt; get_string(&#039;tagsdeleted&#039;, &#039;book&#039;),&lt;br /&gt;
            &#039;error&#039; =&amp;gt; false&lt;br /&gt;
        ];&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return $status;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;core_tag_tag::remove_all_item_tags($component, $itemtype, $itemid, $tiuserid = 0)&#039;&#039;&#039; - removes all tag instances associated with an item.&lt;br /&gt;
* &#039;&#039;&#039;core_tag_tag::delete_instances($component, $itemtype = null, $contextid = null)&#039;&#039;&#039; - deletes tag instances in bulk. Here $component is mandatory in this method, either itemtype or contextid or neither or both can be specified.&lt;br /&gt;
&lt;br /&gt;
===Backup and restore===&lt;br /&gt;
&lt;br /&gt;
When you tag contents inside the course the plugin has to hook into backup and restore and process necessary tags. This is especially important for the contents inside activity modules, such as wiki pages or forum posts. Questions in the course question bank also backup and restore their tags.&lt;br /&gt;
&lt;br /&gt;
You can choose to backup and restore tags for each item individually (as it is done in mod_wiki) OR backup all tags in the context at once (as it is done in mod_glossary or mod_forum). Second option is preferable for performance reasons. Make sure to take into account $userinfo (whether user information is backed up / restored), for example wiki pages is not user information but glossary entries are, tags on them follow the same rule.&lt;br /&gt;
&lt;br /&gt;
This is an example from Glossary module that can be found in &#039;&#039;&#039;backup_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    $tags = new backup_nested_element(&#039;entriestags&#039;);&lt;br /&gt;
    $tag = new backup_nested_element(&#039;tag&#039;, array(&#039;id&#039;), array(&#039;itemid&#039;, &#039;rawname&#039;));&lt;br /&gt;
    // ...&lt;br /&gt;
    $glossary-&amp;gt;add_child($tags); // Note that parent node is the glossary, not glossary entry, however the individual entries are tagged.&lt;br /&gt;
    $tags-&amp;gt;add_child($tag);&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo &amp;amp;&amp;amp; core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) {&lt;br /&gt;
        $tag-&amp;gt;set_source_sql(&#039;SELECT t.id, ti.itemid, t.rawname&lt;br /&gt;
                                FROM {tag} t&lt;br /&gt;
                                JOIN {tag_instance} ti ON ti.tagid = t.id&lt;br /&gt;
                               WHERE ti.itemtype = ?&lt;br /&gt;
                                 AND ti.component = ?&lt;br /&gt;
                                 AND ti.contextid = ?&#039;, array(&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;glossary_entries&#039;),&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;mod_glossary&#039;),&lt;br /&gt;
            backup::VAR_CONTEXTID));&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And this in the &#039;&#039;&#039;restore_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo) {&lt;br /&gt;
        $paths[] = new restore_path_element(&#039;glossary_entry_tag&#039;, &#039;/activity/glossary/entriestags/tag&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
protected function process_glossary_entry_tag($data) {&lt;br /&gt;
    $data = (object)$data;&lt;br /&gt;
&lt;br /&gt;
    if (!core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) { // Tags disabled on this site, nothing to process.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $tag = $data-&amp;gt;rawname;&lt;br /&gt;
    if (!$itemid = $this-&amp;gt;get_mappingid(&#039;glossary_entry&#039;, $data-&amp;gt;itemid)) {&lt;br /&gt;
        // Orphaned tag, we could not find the glossary entry for it - ignore.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $context = context_module::instance($this-&amp;gt;task-&amp;gt;get_moduleid());&lt;br /&gt;
    core_tag_tag::add_item_tag(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;, $itemid, $context, $tag);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Search callback===&lt;br /&gt;
&lt;br /&gt;
This is the most difficult part of Tag API. When user searches for the items tagged with a specific tag only the items user has access to must be returned. Running access check on all items can be very costly. Class &#039;&#039;&#039;core_tag_index_builder&#039;&#039;&#039; can help with retrieving and caching records, especially inside the courses or activity modules.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_wiki_get_tagged_pages($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = 1, $page = 0) {&lt;br /&gt;
    // Find items.&lt;br /&gt;
    // Please refer to existing callbacks in core for examples.&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    // Use core_tag_index_builder to build and filter the list of items. &lt;br /&gt;
    // Notice how we search for 6 items when we need to display 5 - this way we will know that we need to display a link to the next page.&lt;br /&gt;
    $builder = new core_tag_index_builder(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $query, $params, $page * $perpage, $perpage + 1);&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    $items = $builder-&amp;gt;get_items();&lt;br /&gt;
    if (count($items) &amp;gt; $perpage) {&lt;br /&gt;
        $totalpages = $page + 2; // We don&#039;t need exact page count, just indicate that the next page exists.&lt;br /&gt;
        array_pop($items);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Build the display contents.&lt;br /&gt;
    if ($items) {&lt;br /&gt;
        $tagfeed = new core_tag\output\tagfeed();&lt;br /&gt;
        foreach ($items as $item) {&lt;br /&gt;
            $tagfeed-&amp;gt;add(...);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $content = $OUTPUT-&amp;gt;render_from_template(&#039;core_tag/tagfeed&#039;, $tagfeed-&amp;gt;export_for_template($OUTPUT));&lt;br /&gt;
&lt;br /&gt;
        return new core_tag\output\tagindex($tag, &#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $content,&lt;br /&gt;
                $exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===User-specific tags===&lt;br /&gt;
&lt;br /&gt;
It is possible that each tagged item can be tagged by each user independently. Before Moodle 3.0 this was how courses were tagged however from 3.0 tagging courses became more standard. The functionality remains in the API (argument $tiuser to the tagging functions).  In this case both tag list and tag cloud will display all tag instances added by all users but each user will be able to edit only their own.&lt;br /&gt;
&lt;br /&gt;
If developer chooses to implement it in the plugin, they need to also implement the UI when admin or other privileged user can remove or edit the instances of another user. Otherwise if teacher has tagged the course and later resigned there will be no way to change their tags. Also such tag instances need special treatment during backup and restore - they are now considered &amp;quot;user data&amp;quot; and user id mapping should be performed.&lt;br /&gt;
&lt;br /&gt;
===Advanced usages===&lt;br /&gt;
&lt;br /&gt;
Custom plugins may go beyond the standard tags handling and use them without mixing with regular course/user/wiki/blogs tags, hide them from the &amp;quot;Tag search&amp;quot; page and &amp;quot;Tags&amp;quot; block but instead have their own interface to search/categorise using tags. This can be achieved by defining tag collection, make it not searchable and specify a custom URL to link to when the tag is actually displayed. This all can be defined in db/tag.php, see the comments in [https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tag_area::get_collection($component, $itemtype)&#039;&#039;&#039; - will return you the collection that your tag area is in&lt;br /&gt;
* &#039;&#039;&#039;tag_collection::get_tag_cloud()&#039;&#039;&#039; - will return all tags in the collection. There are no API methods to get the tags used in the tag area - this is actually the purpose of tag collections.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[Tag API before 3.1]]&lt;br /&gt;
* [https://docs.moodle.org/en/Managing_tags Managing tags]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53004</id>
		<title>Tag API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53004"/>
		<updated>2017-10-12T10:39:06Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Deleting and clearing tags */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.1}}&lt;br /&gt;
&lt;br /&gt;
==Tag API overview==&lt;br /&gt;
&lt;br /&gt;
The Tag API allows you to assign labels to information in Moodle. This makes finding this information easier and also facilitates the grouping of similar information. The Tag API allows you to create, modify, delete and search tags in the Moodle system. The main tag related functions can be found in the tag/classes/tag.php file. For a through overview of all of the functions available for working with Tags please see methods in core_tag_tag, core_tag_collection and core_tag_area classes, however the following examples should give you a general understanding of how to get started with tags.&lt;br /&gt;
&lt;br /&gt;
This page describes API in Moodle 3.1 and above, for earlier versions see [[Tag API before 3.1]]&lt;br /&gt;
&lt;br /&gt;
==Tag API usage==&lt;br /&gt;
&lt;br /&gt;
When user tags something a &#039;&#039;&#039;tag instance&#039;&#039;&#039; is created in the database linking the item to the actual &#039;&#039;&#039;tag&#039;&#039;&#039;. If tag did not exist before it is created automatically. Do not confuse these two entities - deleting the tag instance does not normally delete tag, however deleting tag deletes all tag instances associated with it. &lt;br /&gt;
&lt;br /&gt;
Developers define &#039;&#039;&#039;tag areas&#039;&#039;&#039; the areas that can be tagged, examples are:&lt;br /&gt;
* blog posts&lt;br /&gt;
* courses&lt;br /&gt;
* users (tags represent user interests)&lt;br /&gt;
* activity modules&lt;br /&gt;
* questions&lt;br /&gt;
* wiki pages&lt;br /&gt;
&lt;br /&gt;
Each tag area is identified by two attributes - component and itemtype. &#039;&#039;Itemtype must be a name of a table in the database.&#039;&#039; Component is the core component or plugin responsible for the tagging. This way the same DB table (for example &#039;user&#039; or &#039;course&#039;) may be independently tagged by several components. Administrator or manager is able to manage the tag areas, collections and tags inside them on the [https://docs.moodle.org/en/Managing_tags Managing tags] page. Users are able to search tags and view all items tagged with them that they have access to.&lt;br /&gt;
&lt;br /&gt;
===Defining a tag area===&lt;br /&gt;
&lt;br /&gt;
First, developer must define the tag areas in the file &#039;&#039;&#039;db/tag.php&#039;&#039;&#039;. This will usually look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$tagareas = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;,  // This must be a name of the database table (without prefix).&lt;br /&gt;
        &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;, // This can be omitted for plugins since it can only be full frankenstyle name of the plugin.&lt;br /&gt;
        &#039;callback&#039; =&amp;gt; &#039;mod_wiki_get_tagged_pages&#039;,&lt;br /&gt;
        &#039;callbackfile&#039; =&amp;gt; &#039;/mod/wiki/locallib.php&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
You will also need to add language string, for the example above it will be &#039;&#039;&#039;$string[&#039;tagarea_wiki_pages&#039;] = &#039;Wiki pages&#039;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There are more options such as specifying the default value for &amp;quot;Standard tags&amp;quot;, having a fixed collection or excluding from search. They can be found in comments in [[https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]]&lt;br /&gt;
&lt;br /&gt;
After making changes to db/tag.php plugin developer must bump the plugin version in &#039;&#039;&#039;version.php&#039;&#039;&#039; and run upgrade script. This usually applies to any changes in the db/ folder.&lt;br /&gt;
&lt;br /&gt;
===Adding tags element to the editing form===&lt;br /&gt;
&lt;br /&gt;
After tag area is defined it should appear on &amp;quot;Manage tags&amp;quot; page. Now it is time to allow users to add/change tags when editing the item. Here is an example from Wiki module:&lt;br /&gt;
&lt;br /&gt;
1. Add a &#039;tags&#039; form element to the editing form:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;tags&#039;, get_string(&#039;tags&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;, &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This element will automatically check if the tag area is disabled by the manager and will not display anything in this case. However if you want to add a header you need to check if tag area is enabled add this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (core_tag_tag::is_enabled(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;)) {&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;header&#039;, &#039;tagshdr&#039;, get_string(&#039;tags&#039;, &#039;tag&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Save the form data&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $form-&amp;gt;get_data()) {&lt;br /&gt;
    // Do some other processing here, if this is a new page (item) you need to insert it in the DB and obtain id.&lt;br /&gt;
    // $pageid = $data-&amp;gt;id;&lt;br /&gt;
    core_tag_tag::set_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $pageid, $modulecontext, $data-&amp;gt;tags);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
It is important to specify the correct context in this function. Note that $data-&amp;gt;tags will always be returned by the form, even if the area is disabled, however core_tag_tag::set_item_tags() will not change or reset tags if the tag area is disabled.&lt;br /&gt;
&lt;br /&gt;
3. Populate the form with existing tags before calling $form-&amp;gt;set_data($data):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$data = $DB-&amp;gt;get_record(&#039;wiki_pages&#039;, array(&#039;id&#039; =&amp;gt; $this-&amp;gt;page-&amp;gt;id)); // Well, it&#039;s more complicated than that of course....&lt;br /&gt;
$data-&amp;gt;tags = core_tag_tag::get_item_tags_array(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $this-&amp;gt;page-&amp;gt;id);&lt;br /&gt;
$form-&amp;gt;set_data($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Always test the code with tag area enabled and disabled.&lt;br /&gt;
&lt;br /&gt;
===Displaying tags next to the item===&lt;br /&gt;
&lt;br /&gt;
Example of displaying of the tags are user interests on the user profile page. User can see the list of interests, each of them is a link that leads to the page that shows all items tagged with this tag.&lt;br /&gt;
&lt;br /&gt;
Here is the code used by Wiki module to display tags the page is tagged with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;tag_list(core_tag_tag::get_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $page-&amp;gt;id), null, &#039;wiki-tags&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting and clearing tags===&lt;br /&gt;
&lt;br /&gt;
Cron will automatically remove tag instances that point to non existing items, however it is a good habit to delete tags when the record is deleted. &#039;&#039;&#039;Please note:&#039;&#039;&#039; You should clear tags when a course has been reset in the reset course callback:&lt;br /&gt;
* &#039;&#039;&#039;core_tag_tag::remove_all_item_tags($component, $itemtype, $itemid, $tiuserid = 0)&#039;&#039;&#039; - removes all tag instances associated with an item&lt;br /&gt;
* &#039;&#039;&#039;core_tag_tag::delete_instances($component, $itemtype = null, $contextid = null)&#039;&#039;&#039; - deletes tag instances in bulk. Here $component is mandatory in this method, either itemtype or contextid or neither or both can be specified.&lt;br /&gt;
&lt;br /&gt;
===Backup and restore===&lt;br /&gt;
&lt;br /&gt;
When you tag contents inside the course the plugin has to hook into backup and restore and process necessary tags. This is especially important for the contents inside activity modules, such as wiki pages or forum posts. Questions in the course question bank also backup and restore their tags.&lt;br /&gt;
&lt;br /&gt;
You can choose to backup and restore tags for each item individually (as it is done in mod_wiki) OR backup all tags in the context at once (as it is done in mod_glossary or mod_forum). Second option is preferable for performance reasons. Make sure to take into account $userinfo (whether user information is backed up / restored), for example wiki pages is not user information but glossary entries are, tags on them follow the same rule.&lt;br /&gt;
&lt;br /&gt;
This is an example from Glossary module that can be found in &#039;&#039;&#039;backup_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    $tags = new backup_nested_element(&#039;entriestags&#039;);&lt;br /&gt;
    $tag = new backup_nested_element(&#039;tag&#039;, array(&#039;id&#039;), array(&#039;itemid&#039;, &#039;rawname&#039;));&lt;br /&gt;
    // ...&lt;br /&gt;
    $glossary-&amp;gt;add_child($tags); // Note that parent node is the glossary, not glossary entry, however the individual entries are tagged.&lt;br /&gt;
    $tags-&amp;gt;add_child($tag);&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo &amp;amp;&amp;amp; core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) {&lt;br /&gt;
        $tag-&amp;gt;set_source_sql(&#039;SELECT t.id, ti.itemid, t.rawname&lt;br /&gt;
                                FROM {tag} t&lt;br /&gt;
                                JOIN {tag_instance} ti ON ti.tagid = t.id&lt;br /&gt;
                               WHERE ti.itemtype = ?&lt;br /&gt;
                                 AND ti.component = ?&lt;br /&gt;
                                 AND ti.contextid = ?&#039;, array(&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;glossary_entries&#039;),&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;mod_glossary&#039;),&lt;br /&gt;
            backup::VAR_CONTEXTID));&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And this in the &#039;&#039;&#039;restore_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo) {&lt;br /&gt;
        $paths[] = new restore_path_element(&#039;glossary_entry_tag&#039;, &#039;/activity/glossary/entriestags/tag&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
protected function process_glossary_entry_tag($data) {&lt;br /&gt;
    $data = (object)$data;&lt;br /&gt;
&lt;br /&gt;
    if (!core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) { // Tags disabled on this site, nothing to process.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $tag = $data-&amp;gt;rawname;&lt;br /&gt;
    if (!$itemid = $this-&amp;gt;get_mappingid(&#039;glossary_entry&#039;, $data-&amp;gt;itemid)) {&lt;br /&gt;
        // Orphaned tag, we could not find the glossary entry for it - ignore.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $context = context_module::instance($this-&amp;gt;task-&amp;gt;get_moduleid());&lt;br /&gt;
    core_tag_tag::add_item_tag(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;, $itemid, $context, $tag);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Search callback===&lt;br /&gt;
&lt;br /&gt;
This is the most difficult part of Tag API. When user searches for the items tagged with a specific tag only the items user has access to must be returned. Running access check on all items can be very costly. Class &#039;&#039;&#039;core_tag_index_builder&#039;&#039;&#039; can help with retrieving and caching records, especially inside the courses or activity modules.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_wiki_get_tagged_pages($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = 1, $page = 0) {&lt;br /&gt;
    // Find items.&lt;br /&gt;
    // Please refer to existing callbacks in core for examples.&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    // Use core_tag_index_builder to build and filter the list of items. &lt;br /&gt;
    // Notice how we search for 6 items when we need to display 5 - this way we will know that we need to display a link to the next page.&lt;br /&gt;
    $builder = new core_tag_index_builder(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $query, $params, $page * $perpage, $perpage + 1);&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    $items = $builder-&amp;gt;get_items();&lt;br /&gt;
    if (count($items) &amp;gt; $perpage) {&lt;br /&gt;
        $totalpages = $page + 2; // We don&#039;t need exact page count, just indicate that the next page exists.&lt;br /&gt;
        array_pop($items);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Build the display contents.&lt;br /&gt;
    if ($items) {&lt;br /&gt;
        $tagfeed = new core_tag\output\tagfeed();&lt;br /&gt;
        foreach ($items as $item) {&lt;br /&gt;
            $tagfeed-&amp;gt;add(...);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $content = $OUTPUT-&amp;gt;render_from_template(&#039;core_tag/tagfeed&#039;, $tagfeed-&amp;gt;export_for_template($OUTPUT));&lt;br /&gt;
&lt;br /&gt;
        return new core_tag\output\tagindex($tag, &#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $content,&lt;br /&gt;
                $exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===User-specific tags===&lt;br /&gt;
&lt;br /&gt;
It is possible that each tagged item can be tagged by each user independently. Before Moodle 3.0 this was how courses were tagged however from 3.0 tagging courses became more standard. The functionality remains in the API (argument $tiuser to the tagging functions).  In this case both tag list and tag cloud will display all tag instances added by all users but each user will be able to edit only their own.&lt;br /&gt;
&lt;br /&gt;
If developer chooses to implement it in the plugin, they need to also implement the UI when admin or other privileged user can remove or edit the instances of another user. Otherwise if teacher has tagged the course and later resigned there will be no way to change their tags. Also such tag instances need special treatment during backup and restore - they are now considered &amp;quot;user data&amp;quot; and user id mapping should be performed.&lt;br /&gt;
&lt;br /&gt;
===Advanced usages===&lt;br /&gt;
&lt;br /&gt;
Custom plugins may go beyond the standard tags handling and use them without mixing with regular course/user/wiki/blogs tags, hide them from the &amp;quot;Tag search&amp;quot; page and &amp;quot;Tags&amp;quot; block but instead have their own interface to search/categorise using tags. This can be achieved by defining tag collection, make it not searchable and specify a custom URL to link to when the tag is actually displayed. This all can be defined in db/tag.php, see the comments in [https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tag_area::get_collection($component, $itemtype)&#039;&#039;&#039; - will return you the collection that your tag area is in&lt;br /&gt;
* &#039;&#039;&#039;tag_collection::get_tag_cloud()&#039;&#039;&#039; - will return all tags in the collection. There are no API methods to get the tags used in the tag area - this is actually the purpose of tag collections.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[Tag API before 3.1]]&lt;br /&gt;
* [https://docs.moodle.org/en/Managing_tags Managing tags]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53003</id>
		<title>Tag API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Tag_API&amp;diff=53003"/>
		<updated>2017-10-12T10:37:52Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle 3.1}}&lt;br /&gt;
&lt;br /&gt;
==Tag API overview==&lt;br /&gt;
&lt;br /&gt;
The Tag API allows you to assign labels to information in Moodle. This makes finding this information easier and also facilitates the grouping of similar information. The Tag API allows you to create, modify, delete and search tags in the Moodle system. The main tag related functions can be found in the tag/classes/tag.php file. For a through overview of all of the functions available for working with Tags please see methods in core_tag_tag, core_tag_collection and core_tag_area classes, however the following examples should give you a general understanding of how to get started with tags.&lt;br /&gt;
&lt;br /&gt;
This page describes API in Moodle 3.1 and above, for earlier versions see [[Tag API before 3.1]]&lt;br /&gt;
&lt;br /&gt;
==Tag API usage==&lt;br /&gt;
&lt;br /&gt;
When user tags something a &#039;&#039;&#039;tag instance&#039;&#039;&#039; is created in the database linking the item to the actual &#039;&#039;&#039;tag&#039;&#039;&#039;. If tag did not exist before it is created automatically. Do not confuse these two entities - deleting the tag instance does not normally delete tag, however deleting tag deletes all tag instances associated with it. &lt;br /&gt;
&lt;br /&gt;
Developers define &#039;&#039;&#039;tag areas&#039;&#039;&#039; the areas that can be tagged, examples are:&lt;br /&gt;
* blog posts&lt;br /&gt;
* courses&lt;br /&gt;
* users (tags represent user interests)&lt;br /&gt;
* activity modules&lt;br /&gt;
* questions&lt;br /&gt;
* wiki pages&lt;br /&gt;
&lt;br /&gt;
Each tag area is identified by two attributes - component and itemtype. &#039;&#039;Itemtype must be a name of a table in the database.&#039;&#039; Component is the core component or plugin responsible for the tagging. This way the same DB table (for example &#039;user&#039; or &#039;course&#039;) may be independently tagged by several components. Administrator or manager is able to manage the tag areas, collections and tags inside them on the [https://docs.moodle.org/en/Managing_tags Managing tags] page. Users are able to search tags and view all items tagged with them that they have access to.&lt;br /&gt;
&lt;br /&gt;
===Defining a tag area===&lt;br /&gt;
&lt;br /&gt;
First, developer must define the tag areas in the file &#039;&#039;&#039;db/tag.php&#039;&#039;&#039;. This will usually look like:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$tagareas = array(&lt;br /&gt;
    array(&lt;br /&gt;
        &#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;,  // This must be a name of the database table (without prefix).&lt;br /&gt;
        &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;, // This can be omitted for plugins since it can only be full frankenstyle name of the plugin.&lt;br /&gt;
        &#039;callback&#039; =&amp;gt; &#039;mod_wiki_get_tagged_pages&#039;,&lt;br /&gt;
        &#039;callbackfile&#039; =&amp;gt; &#039;/mod/wiki/locallib.php&#039;,&lt;br /&gt;
    ),&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
You will also need to add language string, for the example above it will be &#039;&#039;&#039;$string[&#039;tagarea_wiki_pages&#039;] = &#039;Wiki pages&#039;;&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
There are more options such as specifying the default value for &amp;quot;Standard tags&amp;quot;, having a fixed collection or excluding from search. They can be found in comments in [[https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]]&lt;br /&gt;
&lt;br /&gt;
After making changes to db/tag.php plugin developer must bump the plugin version in &#039;&#039;&#039;version.php&#039;&#039;&#039; and run upgrade script. This usually applies to any changes in the db/ folder.&lt;br /&gt;
&lt;br /&gt;
===Adding tags element to the editing form===&lt;br /&gt;
&lt;br /&gt;
After tag area is defined it should appear on &amp;quot;Manage tags&amp;quot; page. Now it is time to allow users to add/change tags when editing the item. Here is an example from Wiki module:&lt;br /&gt;
&lt;br /&gt;
1. Add a &#039;tags&#039; form element to the editing form:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mform-&amp;gt;addElement(&#039;tags&#039;, &#039;tags&#039;, get_string(&#039;tags&#039;), array(&#039;itemtype&#039; =&amp;gt; &#039;wiki_pages&#039;, &#039;component&#039; =&amp;gt; &#039;mod_wiki&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This element will automatically check if the tag area is disabled by the manager and will not display anything in this case. However if you want to add a header you need to check if tag area is enabled add this:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if (core_tag_tag::is_enabled(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;)) {&lt;br /&gt;
    $mform-&amp;gt;addElement(&#039;header&#039;, &#039;tagshdr&#039;, get_string(&#039;tags&#039;, &#039;tag&#039;));&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
2. Save the form data&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
if ($data = $form-&amp;gt;get_data()) {&lt;br /&gt;
    // Do some other processing here, if this is a new page (item) you need to insert it in the DB and obtain id.&lt;br /&gt;
    // $pageid = $data-&amp;gt;id;&lt;br /&gt;
    core_tag_tag::set_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $pageid, $modulecontext, $data-&amp;gt;tags);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
It is important to specify the correct context in this function. Note that $data-&amp;gt;tags will always be returned by the form, even if the area is disabled, however core_tag_tag::set_item_tags() will not change or reset tags if the tag area is disabled.&lt;br /&gt;
&lt;br /&gt;
3. Populate the form with existing tags before calling $form-&amp;gt;set_data($data):&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$data = $DB-&amp;gt;get_record(&#039;wiki_pages&#039;, array(&#039;id&#039; =&amp;gt; $this-&amp;gt;page-&amp;gt;id)); // Well, it&#039;s more complicated than that of course....&lt;br /&gt;
$data-&amp;gt;tags = core_tag_tag::get_item_tags_array(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $this-&amp;gt;page-&amp;gt;id);&lt;br /&gt;
$form-&amp;gt;set_data($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Always test the code with tag area enabled and disabled.&lt;br /&gt;
&lt;br /&gt;
===Displaying tags next to the item===&lt;br /&gt;
&lt;br /&gt;
Example of displaying of the tags are user interests on the user profile page. User can see the list of interests, each of them is a link that leads to the page that shows all items tagged with this tag.&lt;br /&gt;
&lt;br /&gt;
Here is the code used by Wiki module to display tags the page is tagged with:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
echo $OUTPUT-&amp;gt;tag_list(core_tag_tag::get_item_tags(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $page-&amp;gt;id), null, &#039;wiki-tags&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting and clearing tags===&lt;br /&gt;
&lt;br /&gt;
Cron will automatically remove tag instances that point to non existing items, however it is a good habit to delete tags when the record is deleted. *Please note:* You should clear tags when a course has been reset in the reset course callback:&lt;br /&gt;
* &#039;&#039;&#039;core_tag_tag::remove_all_item_tags($component, $itemtype, $itemid, $tiuserid = 0)&#039;&#039;&#039; - removes all tag instances associated with an item&lt;br /&gt;
* &#039;&#039;&#039;core_tag_tag::delete_instances($component, $itemtype = null, $contextid = null)&#039;&#039;&#039; - deletes tag instances in bulk. Here $component is mandatory in this method, either itemtype or contextid or neither or both can be specified.&lt;br /&gt;
&lt;br /&gt;
===Backup and restore===&lt;br /&gt;
&lt;br /&gt;
When you tag contents inside the course the plugin has to hook into backup and restore and process necessary tags. This is especially important for the contents inside activity modules, such as wiki pages or forum posts. Questions in the course question bank also backup and restore their tags.&lt;br /&gt;
&lt;br /&gt;
You can choose to backup and restore tags for each item individually (as it is done in mod_wiki) OR backup all tags in the context at once (as it is done in mod_glossary or mod_forum). Second option is preferable for performance reasons. Make sure to take into account $userinfo (whether user information is backed up / restored), for example wiki pages is not user information but glossary entries are, tags on them follow the same rule.&lt;br /&gt;
&lt;br /&gt;
This is an example from Glossary module that can be found in &#039;&#039;&#039;backup_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    $tags = new backup_nested_element(&#039;entriestags&#039;);&lt;br /&gt;
    $tag = new backup_nested_element(&#039;tag&#039;, array(&#039;id&#039;), array(&#039;itemid&#039;, &#039;rawname&#039;));&lt;br /&gt;
    // ...&lt;br /&gt;
    $glossary-&amp;gt;add_child($tags); // Note that parent node is the glossary, not glossary entry, however the individual entries are tagged.&lt;br /&gt;
    $tags-&amp;gt;add_child($tag);&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo &amp;amp;&amp;amp; core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) {&lt;br /&gt;
        $tag-&amp;gt;set_source_sql(&#039;SELECT t.id, ti.itemid, t.rawname&lt;br /&gt;
                                FROM {tag} t&lt;br /&gt;
                                JOIN {tag_instance} ti ON ti.tagid = t.id&lt;br /&gt;
                               WHERE ti.itemtype = ?&lt;br /&gt;
                                 AND ti.component = ?&lt;br /&gt;
                                 AND ti.contextid = ?&#039;, array(&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;glossary_entries&#039;),&lt;br /&gt;
            backup_helper::is_sqlparam(&#039;mod_glossary&#039;),&lt;br /&gt;
            backup::VAR_CONTEXTID));&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And this in the &#039;&#039;&#039;restore_glossary_stepslib.php&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
protected function define_structure() {&lt;br /&gt;
    // ...&lt;br /&gt;
    if ($userinfo) {&lt;br /&gt;
        $paths[] = new restore_path_element(&#039;glossary_entry_tag&#039;, &#039;/activity/glossary/entriestags/tag&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
protected function process_glossary_entry_tag($data) {&lt;br /&gt;
    $data = (object)$data;&lt;br /&gt;
&lt;br /&gt;
    if (!core_tag_tag::is_enabled(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;)) { // Tags disabled on this site, nothing to process.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $tag = $data-&amp;gt;rawname;&lt;br /&gt;
    if (!$itemid = $this-&amp;gt;get_mappingid(&#039;glossary_entry&#039;, $data-&amp;gt;itemid)) {&lt;br /&gt;
        // Orphaned tag, we could not find the glossary entry for it - ignore.&lt;br /&gt;
        return;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $context = context_module::instance($this-&amp;gt;task-&amp;gt;get_moduleid());&lt;br /&gt;
    core_tag_tag::add_item_tag(&#039;mod_glossary&#039;, &#039;glossary_entries&#039;, $itemid, $context, $tag);&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Search callback===&lt;br /&gt;
&lt;br /&gt;
This is the most difficult part of Tag API. When user searches for the items tagged with a specific tag only the items user has access to must be returned. Running access check on all items can be very costly. Class &#039;&#039;&#039;core_tag_index_builder&#039;&#039;&#039; can help with retrieving and caching records, especially inside the courses or activity modules.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_wiki_get_tagged_pages($tag, $exclusivemode = false, $fromctx = 0, $ctx = 0, $rec = 1, $page = 0) {&lt;br /&gt;
    // Find items.&lt;br /&gt;
    // Please refer to existing callbacks in core for examples.&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    // Use core_tag_index_builder to build and filter the list of items. &lt;br /&gt;
    // Notice how we search for 6 items when we need to display 5 - this way we will know that we need to display a link to the next page.&lt;br /&gt;
    $builder = new core_tag_index_builder(&#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $query, $params, $page * $perpage, $perpage + 1);&lt;br /&gt;
&lt;br /&gt;
    // ...&lt;br /&gt;
&lt;br /&gt;
    $items = $builder-&amp;gt;get_items();&lt;br /&gt;
    if (count($items) &amp;gt; $perpage) {&lt;br /&gt;
        $totalpages = $page + 2; // We don&#039;t need exact page count, just indicate that the next page exists.&lt;br /&gt;
        array_pop($items);&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Build the display contents.&lt;br /&gt;
    if ($items) {&lt;br /&gt;
        $tagfeed = new core_tag\output\tagfeed();&lt;br /&gt;
        foreach ($items as $item) {&lt;br /&gt;
            $tagfeed-&amp;gt;add(...);&lt;br /&gt;
        }&lt;br /&gt;
&lt;br /&gt;
        $content = $OUTPUT-&amp;gt;render_from_template(&#039;core_tag/tagfeed&#039;, $tagfeed-&amp;gt;export_for_template($OUTPUT));&lt;br /&gt;
&lt;br /&gt;
        return new core_tag\output\tagindex($tag, &#039;mod_wiki&#039;, &#039;wiki_pages&#039;, $content,&lt;br /&gt;
                $exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===User-specific tags===&lt;br /&gt;
&lt;br /&gt;
It is possible that each tagged item can be tagged by each user independently. Before Moodle 3.0 this was how courses were tagged however from 3.0 tagging courses became more standard. The functionality remains in the API (argument $tiuser to the tagging functions).  In this case both tag list and tag cloud will display all tag instances added by all users but each user will be able to edit only their own.&lt;br /&gt;
&lt;br /&gt;
If developer chooses to implement it in the plugin, they need to also implement the UI when admin or other privileged user can remove or edit the instances of another user. Otherwise if teacher has tagged the course and later resigned there will be no way to change their tags. Also such tag instances need special treatment during backup and restore - they are now considered &amp;quot;user data&amp;quot; and user id mapping should be performed.&lt;br /&gt;
&lt;br /&gt;
===Advanced usages===&lt;br /&gt;
&lt;br /&gt;
Custom plugins may go beyond the standard tags handling and use them without mixing with regular course/user/wiki/blogs tags, hide them from the &amp;quot;Tag search&amp;quot; page and &amp;quot;Tags&amp;quot; block but instead have their own interface to search/categorise using tags. This can be achieved by defining tag collection, make it not searchable and specify a custom URL to link to when the tag is actually displayed. This all can be defined in db/tag.php, see the comments in [https://github.com/moodle/moodle/blob/master/lib/db/tag.php lib/db/tag.php]&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;tag_area::get_collection($component, $itemtype)&#039;&#039;&#039; - will return you the collection that your tag area is in&lt;br /&gt;
* &#039;&#039;&#039;tag_collection::get_tag_cloud()&#039;&#039;&#039; - will return all tags in the collection. There are no API methods to get the tags used in the tag area - this is actually the purpose of tag collections.&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[Tag API before 3.1]]&lt;br /&gt;
* [https://docs.moodle.org/en/Managing_tags Managing tags]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52555</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52555"/>
		<updated>2017-06-07T11:36:55Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* calendar_get_legacy_events() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Event priority==&lt;br /&gt;
There might be cases that an activity event will have user and/or group overrides. Therefore we need a way to show only the relevant event on the user&#039;s calendar. This is where the &#039;priority&#039; field comes in. &lt;br /&gt;
&lt;br /&gt;
The event priority is set to the following:&lt;br /&gt;
* NULL for non-override events.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;priority = null;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* 0 for user override events.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;priority = CALENDAR_EVENT_USER_OVERRIDE_PRIORITY;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
* A positive integer for group events.&lt;br /&gt;
&lt;br /&gt;
For integer and non-null event priorities, the lower the value, the higher the priority is. Meaning, user overrides always have a higher priority than group overrides. Group override priorities are currently being determined in two ways in core activities:&lt;br /&gt;
# In the assignment module, the event priorities for group overrides are being determined from the &#039;sortorder&#039; column in the &#039;assign_overrides&#039; table.&lt;br /&gt;
# In the lesson and quiz modules, the event priorities for group overrides are being calculated using the functions lesson_get_group_override_priorities($lessonid) and quiz_get_group_override_priorities($quizid).&lt;br /&gt;
&lt;br /&gt;
Should you ever decide to sort out group override priorities by implementing *_get_group_override_priorities(), the recommended return structure would be something like&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
[&lt;br /&gt;
    &#039;youreventtype1&#039; =&amp;gt; $prioritiesforeventtype1, &lt;br /&gt;
    ...&lt;br /&gt;
]&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
where &#039;$prioritiesforeventtype1&#039; is an associative array that has the timestamp of the group override event as key and the calculated priority as value. For more details, please see the implementation for the lesson module below:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Calculates the priorities of timeopen and timeclose values for group overrides for a lesson.&lt;br /&gt;
 *&lt;br /&gt;
 * @param int $lessonid The lesson ID.&lt;br /&gt;
 * @return array|null Array of group override priorities for open and close times. Null if there are no group overrides.&lt;br /&gt;
 */&lt;br /&gt;
function lesson_get_group_override_priorities($lessonid) {&lt;br /&gt;
    global $DB;&lt;br /&gt;
&lt;br /&gt;
    // Fetch group overrides.&lt;br /&gt;
    $where = &#039;lessonid = :lessonid AND groupid IS NOT NULL&#039;;&lt;br /&gt;
    $params = [&#039;lessonid&#039; =&amp;gt; $lessonid];&lt;br /&gt;
    $overrides = $DB-&amp;gt;get_records_select(&#039;lesson_overrides&#039;, $where, $params, &#039;&#039;, &#039;id, groupid, available, deadline&#039;);&lt;br /&gt;
    if (!$overrides) {&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    $grouptimeopen = [];&lt;br /&gt;
    $grouptimeclose = [];&lt;br /&gt;
    foreach ($overrides as $override) {&lt;br /&gt;
        if ($override-&amp;gt;available !== null &amp;amp;&amp;amp; !in_array($override-&amp;gt;available, $grouptimeopen)) {&lt;br /&gt;
            $grouptimeopen[] = $override-&amp;gt;available;&lt;br /&gt;
        }&lt;br /&gt;
        if ($override-&amp;gt;deadline !== null &amp;amp;&amp;amp; !in_array($override-&amp;gt;deadline, $grouptimeclose)) {&lt;br /&gt;
            $grouptimeclose[] = $override-&amp;gt;deadline;&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Sort open times in ascending manner. The earlier open time gets higher priority.&lt;br /&gt;
    sort($grouptimeopen);&lt;br /&gt;
    // Set priorities.&lt;br /&gt;
    $opengrouppriorities = [];&lt;br /&gt;
    $openpriority = 1;&lt;br /&gt;
    foreach ($grouptimeopen as $timeopen) {&lt;br /&gt;
        $opengrouppriorities[$timeopen] = $openpriority++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Sort close times in descending manner. The later close time gets higher priority.&lt;br /&gt;
    rsort($grouptimeclose);&lt;br /&gt;
    // Set priorities.&lt;br /&gt;
    $closegrouppriorities = [];&lt;br /&gt;
    $closepriority = 1;&lt;br /&gt;
    foreach ($grouptimeclose as $timeclose) {&lt;br /&gt;
        $closegrouppriorities[$timeclose] = $closepriority++;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    return [&lt;br /&gt;
        &#039;open&#039; =&amp;gt; $opengrouppriorities,&lt;br /&gt;
        &#039;close&#039; =&amp;gt; $closegrouppriorities&lt;br /&gt;
    ];&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Refreshing calendar events of activity modules==&lt;br /&gt;
A new ad-hoc task  &#039;refresh_mod_calendar_events_task&#039; has been created. This task basically loops through all of the activity modules that implement the &#039;*_refresh_events()&#039; hook.&lt;br /&gt;
&lt;br /&gt;
Sample usage:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// Create the instance.&lt;br /&gt;
$refreshtask = new refresh_mod_calendar_events_task();&lt;br /&gt;
&lt;br /&gt;
// Add custom data.&lt;br /&gt;
$customdata = [&lt;br /&gt;
    &#039;plugins&#039; =&amp;gt; [&#039;assign&#039;, &#039;lesson&#039;, &#039;quiz&#039;] // Optional. If not specified, it will refresh the events of all of the activity modules.&lt;br /&gt;
];&lt;br /&gt;
$refreshtask-&amp;gt;set_custom_data($customdata);&lt;br /&gt;
&lt;br /&gt;
// Queue it.&lt;br /&gt;
\core\task\manager::queue_adhoc_task($refreshtask);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==calendar_get_legacy_events()==&lt;br /&gt;
This functions accepts the same inputs as &#039;calendar_get_events()&#039; but is now utilising the new Moodle Calendar API system. It respects overrides and will also add the action properties, whenever appropriate.&lt;br /&gt;
&lt;br /&gt;
==Changes to Behat==&lt;br /&gt;
The &amp;quot;And I follow &amp;quot;Course1&amp;quot;&amp;quot; Behat step won&#039;t work from the Dashboard anymore and has been replaced with &amp;quot;And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;quot; where &#039;Course 1&#039; is the fullname of the course.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52336</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52336"/>
		<updated>2017-05-10T05:04:24Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Changes to Behat */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changes to Behat==&lt;br /&gt;
The &amp;quot;And I follow &amp;quot;Course1&amp;quot;&amp;quot; Behat step won&#039;t work from the Dashboard anymore and has been replaced with &amp;quot;And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;quot; where &#039;Course 1&#039; is the fullname of the course.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52335</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52335"/>
		<updated>2017-05-10T05:01:54Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Changes to Behat */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changes to Behat==&lt;br /&gt;
The &amp;quot;And I follow &amp;quot;Course1&amp;quot;&amp;quot; Behat step won&#039;t work from the Dashboard anymore and has been replaced with &amp;quot;And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;quot; where &#039;Course 1&#039; is the name of the course.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52334</id>
		<title>Block myoverview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52334"/>
		<updated>2017-05-10T04:58:14Z</updated>

		<summary type="html">&lt;p&gt;Markn: Redirected page to Calendar API#Action events&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;#REDIRECT [[Calendar_API#Action_events]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52333</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52333"/>
		<updated>2017-05-10T04:54:57Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_provide_event_action() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&amp;lt;br /&amp;gt;&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changes to Behat==&lt;br /&gt;
The &amp;quot;And I follow &amp;quot;Course1&amp;quot;&amp;quot; Behat step won&#039;t work from the Dashboard anymore and has been replaced with &amp;quot;And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;quot;. (&#039;Course 1&#039; being the name of the course).&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52332</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52332"/>
		<updated>2017-05-10T04:53:58Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_provide_event_action() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;br /&amp;gt;&lt;br /&gt;
The variables to pass to &amp;lt;code php&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changes to Behat==&lt;br /&gt;
The &amp;quot;And I follow &amp;quot;Course1&amp;quot;&amp;quot; Behat step won&#039;t work from the Dashboard anymore and has been replaced with &amp;quot;And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;quot;. (&#039;Course 1&#039; being the name of the course).&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52331</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52331"/>
		<updated>2017-05-10T04:52:42Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changes to Behat==&lt;br /&gt;
The &amp;quot;And I follow &amp;quot;Course1&amp;quot;&amp;quot; Behat step won&#039;t work from the Dashboard anymore and has been replaced with &amp;quot;And I am on &amp;quot;Course 1&amp;quot; course homepage&amp;quot;. (&#039;Course 1&#039; being the name of the course).&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52330</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52330"/>
		<updated>2017-05-10T04:08:46Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_provide_event_action() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown in block_myoverview (but will still be shown in the calendar block). This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52329</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52329"/>
		<updated>2017-05-10T03:57:17Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_is_event_visible(calendar_event $event) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible()====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52328</id>
		<title>Block myoverview</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Block_myoverview&amp;diff=52328"/>
		<updated>2017-05-10T03:47:53Z</updated>

		<summary type="html">&lt;p&gt;Markn: Created page with &amp;quot;Please see https://docs.moodle.org/dev/Calendar_API#Action_events.&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Please see https://docs.moodle.org/dev/Calendar_API#Action_events.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52317</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52317"/>
		<updated>2017-05-09T09:04:45Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Action events */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION. The events are also sorted on the dashboard by the value specified in the &#039;timesort&#039; field (unixtime) for the event.&lt;br /&gt;
&lt;br /&gt;
Example of the changes to the above code would be to change the &#039;type&#039; and to specify the &#039;timesort&#039; value.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_ACTION;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeclose;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52316</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52316"/>
		<updated>2017-05-09T09:01:39Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Creating an event */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52315</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52315"/>
		<updated>2017-05-09T09:00:46Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Action events */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
There are 3 callbacks your module can implement that are used to control when and how your action is shown to the user.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52314</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52314"/>
		<updated>2017-05-09T08:55:07Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_is_event_visible(calendar_event $event) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Is the event visible?&lt;br /&gt;
 *&lt;br /&gt;
 * This is used to determine global visibility of an event in all places throughout Moodle. For example,&lt;br /&gt;
 * the ASSIGN_EVENT_TYPE_GRADINGDUE event will not be shown to students on their calendar, and&lt;br /&gt;
 * ASSIGN_EVENT_TYPE_DUE events will not be shown to teachers.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event&lt;br /&gt;
 * @return bool Returns true if the event is visible to the current user, false otherwise.&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_is_event_visible(calendar_event $event) {&lt;br /&gt;
    global $CFG, $USER;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/assign/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;assign&#039;][$event-&amp;gt;instance];&lt;br /&gt;
    $context = context_module::instance($cm-&amp;gt;id);&lt;br /&gt;
&lt;br /&gt;
    $assign = new assign($context, $cm, null);&lt;br /&gt;
&lt;br /&gt;
    if ($event-&amp;gt;eventtype == ASSIGN_EVENT_TYPE_GRADINGDUE) {&lt;br /&gt;
        return $assign-&amp;gt;can_grade();&lt;br /&gt;
    } else {&lt;br /&gt;
        return !$assign-&amp;gt;can_grade() &amp;amp;&amp;amp; $assign-&amp;gt;can_view_submission($USER-&amp;gt;id);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52313</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52313"/>
		<updated>2017-05-09T08:53:52Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count()====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Callback function that determines whether an action event should be showing its item count&lt;br /&gt;
 * based on the event type and the item count.&lt;br /&gt;
 *&lt;br /&gt;
 * @param calendar_event $event The calendar event.&lt;br /&gt;
 * @param int $itemcount The item count associated with the action event.&lt;br /&gt;
 * @return bool&lt;br /&gt;
 */&lt;br /&gt;
function mod_assign_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0) {&lt;br /&gt;
    // List of event types where the action event&#039;s item count should be shown.&lt;br /&gt;
    $eventtypesshowingitemcount = [&lt;br /&gt;
        ASSIGN_EVENT_TYPE_GRADINGDUE&lt;br /&gt;
    ];&lt;br /&gt;
    // For mod_assign, item count should be shown if the event type is &#039;gradingdue&#039; and there is one or more item count.&lt;br /&gt;
    return in_array($event-&amp;gt;eventtype, $eventtypesshowingitemcount) &amp;amp;&amp;amp; $itemcount &amp;gt; 0;&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52312</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52312"/>
		<updated>2017-05-09T08:47:51Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
====mod_xyz_core_calendar_provide_event_action()====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;/code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0)====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52311</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52311"/>
		<updated>2017-05-09T08:45:55Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
====mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory)====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none in which case the event will not be shown. This is used by the block_myoverview plugin. If you do not implement this function then the events created by your plugin will not be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
function mod_scorm_core_calendar_provide_event_action(calendar_event $event,&lt;br /&gt;
        \core_calendar\action_factory $factory) {&lt;br /&gt;
    global $CFG;&lt;br /&gt;
&lt;br /&gt;
    require_once($CFG-&amp;gt;dirroot . &#039;/mod/scorm/locallib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
    $cm = get_fast_modinfo($event-&amp;gt;courseid)-&amp;gt;instances[&#039;scorm&#039;][$event-&amp;gt;instance];&lt;br /&gt;
&lt;br /&gt;
    if (!empty($cm-&amp;gt;customdata[&#039;timeclose&#039;]) &amp;amp;&amp;amp; $cm-&amp;gt;customdata[&#039;timeclose&#039;] &amp;lt; time()) {&lt;br /&gt;
        // The scorm has closed so the user can no longer submit anything.&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    // Restore scorm object from cached values in $cm, we only need id, timeclose and timeopen.&lt;br /&gt;
    $customdata = $cm-&amp;gt;customdata ?: [];&lt;br /&gt;
    $customdata[&#039;id&#039;] = $cm-&amp;gt;instance;&lt;br /&gt;
    $scorm = (object)($customdata + [&#039;timeclose&#039; =&amp;gt; 0, &#039;timeopen&#039; =&amp;gt; 0]);&lt;br /&gt;
&lt;br /&gt;
    // Check that the SCORM activity is open.&lt;br /&gt;
    list($actionable, $warnings) = scorm_get_availability_status($scorm);&lt;br /&gt;
&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        get_string(&#039;enter&#039;, &#039;scorm&#039;),&lt;br /&gt;
        new \moodle_url(&#039;/mod/scorm/view.php&#039;, array(&#039;id&#039; =&amp;gt; $cm-&amp;gt;id)),&lt;br /&gt;
        1,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The variables to pass to &amp;lt;code&amp;gt;create_instance()&amp;lt;code&amp;gt; are -&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0)====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52304</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52304"/>
		<updated>2017-05-09T08:29:02Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory) */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
====mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory)====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none (in which case the event will not be shown). This is used by the new block_myoverview plugin. If you do not implement this function then the events created by your plugin will never be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        $name,&lt;br /&gt;
        $url,&lt;br /&gt;
        $itemcount,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
# $name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
# $url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
# $itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
# $actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0)====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52301</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52301"/>
		<updated>2017-05-09T08:04:25Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==Creating an event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
====mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory)====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none (in which case the event will not be shown). This is used by the new block_myoverview plugin. If you do not implement this function then the events created by your plugin will never be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        $name,&lt;br /&gt;
        $url,&lt;br /&gt;
        $itemcount,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
$name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
$url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
$itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
$actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0)====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52299</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52299"/>
		<updated>2017-05-09T07:14:29Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{ Moodle 3.3 }}&lt;br /&gt;
&lt;br /&gt;
This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==The calendar_event class==&lt;br /&gt;
&lt;br /&gt;
The general functionality of the calendar_event() class is to create, update and delete events.&lt;br /&gt;
&lt;br /&gt;
==Creating a new event==&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Updating an event==&lt;br /&gt;
You can update an existing event in database by providing at least the event id. If the event is a part of a chain of repeated events, the rest of series event will also be updated (depending on the value of property repeateditall). This function could also be used to insert new event to database, if the given event does not exist yes. The optional parameter $checkcapability is used to check user&#039;s capability to edit/add events. By default the $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Deleting an event==&lt;br /&gt;
You can delete an existing event from the database. The optional parameter $deleterepeated is used as an indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also delete all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Action events==&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
===The callbacks===&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_is_event_visible(calendar_event $event)====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
====mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory)====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none (in which case the event will not be shown). This is used by the new block_myoverview plugin. If you do not implement this function then the events created by your plugin will never be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        $name,&lt;br /&gt;
        $url,&lt;br /&gt;
        $itemcount,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
$name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
$url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
$itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
$actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
====mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0)====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52129</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52129"/>
		<updated>2017-04-07T05:47:52Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Action events */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==The calendar_event class==&lt;br /&gt;
&lt;br /&gt;
In general functionality of the calendar_event() class is to create, update and delete events.&lt;br /&gt;
&lt;br /&gt;
===Creating a new event===&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating an event===&lt;br /&gt;
Updating an existing event in database by providing at least an event id. If the event is a repeated events, the rest of series event will also be updated (depending on the properties value of repeateditall). This function could also be use to insert new event to database If the requested event is not exist in database. The optional parameter $checkcapability is use to check user&#039;s capability to edit/add event. By default $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting an event===&lt;br /&gt;
Deleting an existing event in database. The optional parameter $deleterepeated is use as indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also deleting all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Action events===&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my overview sam student.png]]&lt;br /&gt;
&lt;br /&gt;
====The callbacks====&lt;br /&gt;
&lt;br /&gt;
=====mod_xyz_core_calendar_is_event_visible(calendar_event $event)=====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
=====mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory)=====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none (in which case the event will not be shown). This is used by the new block_myoverview plugin. If you do not implement this function then the events created by your plugin will never be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        $name,&lt;br /&gt;
        $url,&lt;br /&gt;
        $itemcount,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
$name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
$url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
$itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
$actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
=====mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0)=====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=File:my_overview_sam_student.png&amp;diff=52128</id>
		<title>File:my overview sam student.png</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=File:my_overview_sam_student.png&amp;diff=52128"/>
		<updated>2017-04-07T05:46:07Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52127</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52127"/>
		<updated>2017-04-07T05:45:46Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page documents the Calendar API as it is in Moodle 3.3 and later. For the API in older versions of Moodle, see [[Calendar_API_old]].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add, modify and delete events in the calendar for user, groups, courses and the site. As of 3.3 it also allows you to provide actions for these events so that they are then displayed on block_myoverview, which by default is shown on users&#039; dashboard.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events to users. These events are generated by other plugins, like activities, to let the user know of an important date. For example, when an assignment opens for submission.&lt;br /&gt;
&lt;br /&gt;
The block_myoverview plugin displays calendar events that have an action associated with them. For example, an activity may have a due date specified, in which case it will create a calendar action event so that the event will display on the dashboard for the user, as well as the calendar. In order to provide the action associated for this event you have to define a callback in your plugin which is detailed below.&lt;br /&gt;
&lt;br /&gt;
==The calendar_event class==&lt;br /&gt;
&lt;br /&gt;
In general functionality of the calendar_event() class is to create, update and delete events.&lt;br /&gt;
&lt;br /&gt;
===Creating a new event===&lt;br /&gt;
Creating a new calendar event. &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot.&#039;/calendar/lib.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$event = new stdClass();&lt;br /&gt;
$event-&amp;gt;eventtype = SCORM_EVENT_TYPE_OPEN; // Constant defined somewhere in your code - this can be any string value you want. It is a way to identify the event.&lt;br /&gt;
$event-&amp;gt;type = CALENDAR_EVENT_TYPE_STANDARD; // This is used for events we only want to display on the calendar, and are not needed on the block_myoverview.&lt;br /&gt;
$event-&amp;gt;name = get_string(&#039;calendarstart&#039;, &#039;scorm&#039;, $scorm-&amp;gt;name);&lt;br /&gt;
$event-&amp;gt;description = format_module_intro(&#039;scorm&#039;, $scorm, $cmid);&lt;br /&gt;
$event-&amp;gt;courseid = $scorm-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid = 0;&lt;br /&gt;
$event-&amp;gt;userid = 0;&lt;br /&gt;
$event-&amp;gt;modulename = &#039;scorm&#039;;&lt;br /&gt;
$event-&amp;gt;instance = $scorm-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;timestart = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;timesort = $scorm-&amp;gt;timeopen;&lt;br /&gt;
$event-&amp;gt;visible = instance_is_visible(&#039;scorm&#039;, $scorm);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating an event===&lt;br /&gt;
Updating an existing event in database by providing at least an event id. If the event is a repeated events, the rest of series event will also be updated (depending on the properties value of repeateditall). This function could also be use to insert new event to database If the requested event is not exist in database. The optional parameter $checkcapability is use to check user&#039;s capability to edit/add event. By default $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting an event===&lt;br /&gt;
Deleting an existing event in database. The optional parameter $deleterepeated is use as indicator to remove the rest of repeated events. The default value for $deleterepeated is true. Deleting an event will also deleting all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Action events===&lt;br /&gt;
&lt;br /&gt;
Action events are calendar events that can be actioned. E.g. A student submitting an assignment by a certain date. These events are displayed on the block_myoverview which by default is on users&#039; dashboard. Creating these is the same as creating a normal calendar event except instead of using CALENDAR_EVENT_TYPE_STANDARD as your calendar event type, you use CALENDAR_EVENT_TYPE_ACTION.&lt;br /&gt;
&lt;br /&gt;
[[File:my_overview_sam_student.png]]&lt;br /&gt;
&lt;br /&gt;
====The callbacks====&lt;br /&gt;
&lt;br /&gt;
=====mod_xyz_core_calendar_is_event_visible(calendar_event $event)=====&lt;br /&gt;
This callback determines if an event should be visible throughout the site. For example, the assignment module creates a grading event for teachers. We do not want this event being visible to users who can not perform this action (eg. students), so we return false for those users. If you do not implement this function then the event will always be visible.&lt;br /&gt;
  &lt;br /&gt;
=====mod_xyz_core_calendar_core_calendar_provide_event_action(calendar_event $event, \core_calendar\action_factory $factory)=====&lt;br /&gt;
This function takes a calendar event and provides the action associated with it, or null if there is none (in which case the event will not be shown). This is used by the new block_myoverview plugin. If you do not implement this function then the events created by your plugin will never be shown on the block.&lt;br /&gt;
&lt;br /&gt;
Eg.&lt;br /&gt;
    return $factory-&amp;gt;create_instance(&lt;br /&gt;
        $name,&lt;br /&gt;
        $url,&lt;br /&gt;
        $itemcount,&lt;br /&gt;
        $actionable&lt;br /&gt;
    );&lt;br /&gt;
&lt;br /&gt;
$name String The name of the event, eg. get_string(&#039;dosomething&#039;, &#039;mod_xyz&#039;).&lt;br /&gt;
$url \moodle_url The URL the user visits in order to perform this action.&lt;br /&gt;
$itemcount int This represents the number of items that require action (eg. Need to write 3 forum posts). If this is 0 then the event is not displayed.&lt;br /&gt;
$actionable bool This determines if the event is currently able to be acted on. Eg. the activity may not currently be open due to date restrictions so the event is shown to the user to let them know that there is an upcoming event but the url will not be active.&lt;br /&gt;
&lt;br /&gt;
=====mod_xyz_core_calendar_event_action_shows_item_count(calendar_event $event, $itemcount = 0)=====&lt;br /&gt;
This function determines if a given event should display the number of items to action on block_myoverview. For example, if the event type is ASSIGN_EVENT_TYPE_GRADINGDUE then we only display the item count if there are one or more assignments to grade. If you do not implement this function then the item count is always hidden. This is usually fine as the majority of events only have an item count of &#039;1&#039; (eg. Submitting an assignment) and there is no need display the item count.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52121</id>
		<title>Calendar API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API&amp;diff=52121"/>
		<updated>2017-04-06T06:30:53Z</updated>

		<summary type="html">&lt;p&gt;Markn: Replaced content with &amp;quot;These are the new docs (written for 3.3) for the calendar API, for the older version please see [https://docs.moodle.org/dev/Calendar_API_old Calendar API].  The Calendar...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are the new docs (written for 3.3) for the calendar API, for the older version please see [https://docs.moodle.org/dev/Calendar_API_old Calendar API].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add and modify events in the calendar for user, groups, courses, or the whole site.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API_old&amp;diff=52120</id>
		<title>Calendar API old</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API_old&amp;diff=52120"/>
		<updated>2017-04-06T06:30:34Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are the old docs for the calendar API, for the newer version please see [https://docs.moodle.org/dev/Calendar_API Calendar API].&lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add and modify events in the calendar for user, groups, courses, or the whole site.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events from everything users have access to.&lt;br /&gt;
&lt;br /&gt;
If your plugin generates calendar events (such as due dates) then you need to add your events to the calendar.&lt;br /&gt;
&lt;br /&gt;
==File locations==&lt;br /&gt;
&lt;br /&gt;
All the calendar code is located in /calendar/lib.php.  You need to include this file in your script if you intend to use it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The calendar_event class==&lt;br /&gt;
&lt;br /&gt;
In general functionality of calendar_event() class are to create, update and delete events.&lt;br /&gt;
&lt;br /&gt;
===Creating new event===&lt;br /&gt;
Creating new calendar event to database by defining some properties for the event.  &lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to create event for the hook.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event::create($properties)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating event===&lt;br /&gt;
Updating an existing event in database by providing at least an event id.  If the event is a repeated events, the rest of series event will also be updated (depending on the properties value of repeateditall).  This function could also be use to insert new event to database If the requested event is not exist in database.  The optional parameter $checkcapability is use to check user&#039;s capability to edit/add event.  By default $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to update the hook event.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event::update($data, $checkcapability = true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting event===&lt;br /&gt;
Deleting an existing event in database.  The optional parameter $deleterepeated is use as indicator to remove the rest of repeated events.  The default value for $deleterepeated is true. Deleting an event will also deleting all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to delete event for the hook.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$calendar_event = new calendar_event($event_data);&lt;br /&gt;
$calendar_event-&amp;gt;delete($deleterepeated = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Event hook===&lt;br /&gt;
The capability to use hook to perform specific action to calendar event.  This requires setting up $CFG-&amp;gt;calendar and include external calendar file in $CFG-&amp;gt;dirroot .&#039;/calendar/&#039;. $CFG-&amp;gt;calendar .&#039;/lib.php&#039;).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event_hook($action, array $args)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
List of function for calendar and calendar_event.&lt;br /&gt;
&lt;br /&gt;
===Retrieve or print calendar&#039;s information===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_get_default_courses()&lt;br /&gt;
calendar_get_days()&lt;br /&gt;
calendar_get_starting_weekday()&lt;br /&gt;
calendar_day_representation($tstamp, $now = false, $usecommonwords = true)&lt;br /&gt;
calendar_time_representation($time)&lt;br /&gt;
calendar_wday_name($englishname)&lt;br /&gt;
calendar_days_in_month($month, $year)&lt;br /&gt;
calendar_get_link_href($linkbase, $d, $m, $y)&lt;br /&gt;
calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_year = false)&lt;br /&gt;
calendar_get_popup($is_today, $event_timestart, $popupcontent = &#039;&#039;) &lt;br /&gt;
calendar_add_month($month, $year)&lt;br /&gt;
calendar_sub_month($month, $year)&lt;br /&gt;
calendar_get_module_cached(&amp;amp;$coursecache, $modulename, $instance) &lt;br /&gt;
calendar_get_course_cached(&amp;amp;$coursecache, $courseid)&lt;br /&gt;
calendar_print_month_selector($name, $selected)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Control calendar display===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_top_controls($type, $data)&lt;br /&gt;
calendar_filter_controls(moodle_url $returnurl)&lt;br /&gt;
calendar_preferences_button(stdClass $course)&lt;br /&gt;
calendar_set_filters(array $courseeventsfrom, $ignorefilters = false)&lt;br /&gt;
calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide = false)&lt;br /&gt;
calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Retrieve calendar_event information===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_get_allowed_types(&amp;amp;$allowed, $course = null)&lt;br /&gt;
calendar_add_event_allowed($event) &lt;br /&gt;
calendar_edit_event_allowed($event)&lt;br /&gt;
calendar_user_can_add_event($course)&lt;br /&gt;
calendar_show_event_type($type, $user = null)&lt;br /&gt;
calendar_set_event_type_display($type, $display = null, $user = null)&lt;br /&gt;
calendar_get_events($tstart, $tend, $users, $groups, $courses, $withduration = true, $ignorehidden = true)&lt;br /&gt;
calendar_events_by_day($events, $month, $year, &amp;amp;$eventsbyday, &amp;amp;$durationbyday, &amp;amp;$typesbyday, &amp;amp;$courses) &lt;br /&gt;
calendar_get_upcoming($courses, $groups, $users, $daysinfuture, $maxevents, $fromtime = 0)&lt;br /&gt;
calendar_get_block_upcoming($events, $linkhref = NULL)&lt;br /&gt;
calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime = 0)&lt;br /&gt;
calendar_add_event_metadata($event)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
The following are examples of using the basic calendar_event API in Moodle.&lt;br /&gt;
&lt;br /&gt;
===Example to create new event===&lt;br /&gt;
Creating new calendar event for closing feedback date.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = new stdClass;&lt;br /&gt;
$event-&amp;gt;name         = get_string(&#039;stop&#039;, &#039;feedback&#039;).&#039; &#039;.$feedback-&amp;gt;name;&lt;br /&gt;
$event-&amp;gt;description  = format_module_intro(&#039;feedback&#039;, $feedback, $feedback-&amp;gt;coursemodule);&lt;br /&gt;
$event-&amp;gt;courseid     = $feedback-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid      = 0;&lt;br /&gt;
$event-&amp;gt;userid       = 0;&lt;br /&gt;
$event-&amp;gt;modulename   = &#039;feedback&#039;;&lt;br /&gt;
$event-&amp;gt;instance     = $feedback-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;eventtype    = &#039;feedbackcloses&#039;; // For activity module&#039;s events, this can be used to set the alternative text of the event icon. Set it to &#039;pluginname&#039; unless you have a better string.&lt;br /&gt;
$event-&amp;gt;timestart    = $feedback-&amp;gt;timeclose;&lt;br /&gt;
$event-&amp;gt;visible      = instance_is_visible(&#039;feedback&#039;, $feedback);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating existing calendar event===&lt;br /&gt;
Simple example of updating exiting event through moodle form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting existing calendar event===&lt;br /&gt;
Simple example of deleting existing event from database.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[:en:Calendar|Calendar user docs]]&lt;br /&gt;
* [[Calendar types]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API_old&amp;diff=52119</id>
		<title>Calendar API old</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API_old&amp;diff=52119"/>
		<updated>2017-04-06T06:28:39Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;These are the old docs for the calendar API, for the newer version please see &lt;br /&gt;
&lt;br /&gt;
The Calendar API allows you to add and modify events in the calendar for user, groups, courses, or the whole site.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events from everything users have access to.&lt;br /&gt;
&lt;br /&gt;
If your plugin generates calendar events (such as due dates) then you need to add your events to the calendar.&lt;br /&gt;
&lt;br /&gt;
==File locations==&lt;br /&gt;
&lt;br /&gt;
All the calendar code is located in /calendar/lib.php.  You need to include this file in your script if you intend to use it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The calendar_event class==&lt;br /&gt;
&lt;br /&gt;
In general functionality of calendar_event() class are to create, update and delete events.&lt;br /&gt;
&lt;br /&gt;
===Creating new event===&lt;br /&gt;
Creating new calendar event to database by defining some properties for the event.  &lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to create event for the hook.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event::create($properties)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating event===&lt;br /&gt;
Updating an existing event in database by providing at least an event id.  If the event is a repeated events, the rest of series event will also be updated (depending on the properties value of repeateditall).  This function could also be use to insert new event to database If the requested event is not exist in database.  The optional parameter $checkcapability is use to check user&#039;s capability to edit/add event.  By default $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to update the hook event.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event::update($data, $checkcapability = true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting event===&lt;br /&gt;
Deleting an existing event in database.  The optional parameter $deleterepeated is use as indicator to remove the rest of repeated events.  The default value for $deleterepeated is true. Deleting an event will also deleting all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to delete event for the hook.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$calendar_event = new calendar_event($event_data);&lt;br /&gt;
$calendar_event-&amp;gt;delete($deleterepeated = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Event hook===&lt;br /&gt;
The capability to use hook to perform specific action to calendar event.  This requires setting up $CFG-&amp;gt;calendar and include external calendar file in $CFG-&amp;gt;dirroot .&#039;/calendar/&#039;. $CFG-&amp;gt;calendar .&#039;/lib.php&#039;).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event_hook($action, array $args)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
List of function for calendar and calendar_event.&lt;br /&gt;
&lt;br /&gt;
===Retrieve or print calendar&#039;s information===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_get_default_courses()&lt;br /&gt;
calendar_get_days()&lt;br /&gt;
calendar_get_starting_weekday()&lt;br /&gt;
calendar_day_representation($tstamp, $now = false, $usecommonwords = true)&lt;br /&gt;
calendar_time_representation($time)&lt;br /&gt;
calendar_wday_name($englishname)&lt;br /&gt;
calendar_days_in_month($month, $year)&lt;br /&gt;
calendar_get_link_href($linkbase, $d, $m, $y)&lt;br /&gt;
calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_year = false)&lt;br /&gt;
calendar_get_popup($is_today, $event_timestart, $popupcontent = &#039;&#039;) &lt;br /&gt;
calendar_add_month($month, $year)&lt;br /&gt;
calendar_sub_month($month, $year)&lt;br /&gt;
calendar_get_module_cached(&amp;amp;$coursecache, $modulename, $instance) &lt;br /&gt;
calendar_get_course_cached(&amp;amp;$coursecache, $courseid)&lt;br /&gt;
calendar_print_month_selector($name, $selected)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Control calendar display===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_top_controls($type, $data)&lt;br /&gt;
calendar_filter_controls(moodle_url $returnurl)&lt;br /&gt;
calendar_preferences_button(stdClass $course)&lt;br /&gt;
calendar_set_filters(array $courseeventsfrom, $ignorefilters = false)&lt;br /&gt;
calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide = false)&lt;br /&gt;
calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Retrieve calendar_event information===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_get_allowed_types(&amp;amp;$allowed, $course = null)&lt;br /&gt;
calendar_add_event_allowed($event) &lt;br /&gt;
calendar_edit_event_allowed($event)&lt;br /&gt;
calendar_user_can_add_event($course)&lt;br /&gt;
calendar_show_event_type($type, $user = null)&lt;br /&gt;
calendar_set_event_type_display($type, $display = null, $user = null)&lt;br /&gt;
calendar_get_events($tstart, $tend, $users, $groups, $courses, $withduration = true, $ignorehidden = true)&lt;br /&gt;
calendar_events_by_day($events, $month, $year, &amp;amp;$eventsbyday, &amp;amp;$durationbyday, &amp;amp;$typesbyday, &amp;amp;$courses) &lt;br /&gt;
calendar_get_upcoming($courses, $groups, $users, $daysinfuture, $maxevents, $fromtime = 0)&lt;br /&gt;
calendar_get_block_upcoming($events, $linkhref = NULL)&lt;br /&gt;
calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime = 0)&lt;br /&gt;
calendar_add_event_metadata($event)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
The following are examples of using the basic calendar_event API in Moodle.&lt;br /&gt;
&lt;br /&gt;
===Example to create new event===&lt;br /&gt;
Creating new calendar event for closing feedback date.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = new stdClass;&lt;br /&gt;
$event-&amp;gt;name         = get_string(&#039;stop&#039;, &#039;feedback&#039;).&#039; &#039;.$feedback-&amp;gt;name;&lt;br /&gt;
$event-&amp;gt;description  = format_module_intro(&#039;feedback&#039;, $feedback, $feedback-&amp;gt;coursemodule);&lt;br /&gt;
$event-&amp;gt;courseid     = $feedback-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid      = 0;&lt;br /&gt;
$event-&amp;gt;userid       = 0;&lt;br /&gt;
$event-&amp;gt;modulename   = &#039;feedback&#039;;&lt;br /&gt;
$event-&amp;gt;instance     = $feedback-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;eventtype    = &#039;feedbackcloses&#039;; // For activity module&#039;s events, this can be used to set the alternative text of the event icon. Set it to &#039;pluginname&#039; unless you have a better string.&lt;br /&gt;
$event-&amp;gt;timestart    = $feedback-&amp;gt;timeclose;&lt;br /&gt;
$event-&amp;gt;visible      = instance_is_visible(&#039;feedback&#039;, $feedback);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating existing calendar event===&lt;br /&gt;
Simple example of updating exiting event through moodle form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting existing calendar event===&lt;br /&gt;
Simple example of deleting existing event from database.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[:en:Calendar|Calendar user docs]]&lt;br /&gt;
* [[Calendar types]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Calendar_API_old&amp;diff=52118</id>
		<title>Calendar API old</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Calendar_API_old&amp;diff=52118"/>
		<updated>2017-04-06T06:27:13Z</updated>

		<summary type="html">&lt;p&gt;Markn: Created page with &amp;quot;The Calendar API allows you to add and modify events in the calendar for user, groups, courses, or the whole site.  ==Overview==  The Moodle Calendar collects...&amp;quot;&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Calendar API allows you to add and modify events in the calendar for user, groups, courses, or the whole site.&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
The Moodle [[:en:Calendar|Calendar]] collects and displays calendar events from everything users have access to.&lt;br /&gt;
&lt;br /&gt;
If your plugin generates calendar events (such as due dates) then you need to add your events to the calendar.&lt;br /&gt;
&lt;br /&gt;
==File locations==&lt;br /&gt;
&lt;br /&gt;
All the calendar code is located in /calendar/lib.php.  You need to include this file in your script if you intend to use it.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==The calendar_event class==&lt;br /&gt;
&lt;br /&gt;
In general functionality of calendar_event() class are to create, update and delete events.&lt;br /&gt;
&lt;br /&gt;
===Creating new event===&lt;br /&gt;
Creating new calendar event to database by defining some properties for the event.  &lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to create event for the hook.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event::create($properties)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating event===&lt;br /&gt;
Updating an existing event in database by providing at least an event id.  If the event is a repeated events, the rest of series event will also be updated (depending on the properties value of repeateditall).  This function could also be use to insert new event to database If the requested event is not exist in database.  The optional parameter $checkcapability is use to check user&#039;s capability to edit/add event.  By default $checkcapability parameter is set to true.  &lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to update the hook event.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event::update($data, $checkcapability = true)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting event===&lt;br /&gt;
Deleting an existing event in database.  The optional parameter $deleterepeated is use as indicator to remove the rest of repeated events.  The default value for $deleterepeated is true. Deleting an event will also deleting all associated files related to the event&#039;s editor context.&lt;br /&gt;
&lt;br /&gt;
If event hook is used, it will also call self::calendar_event_hook() to delete event for the hook.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$calendar_event = new calendar_event($event_data);&lt;br /&gt;
$calendar_event-&amp;gt;delete($deleterepeated = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Event hook===&lt;br /&gt;
The capability to use hook to perform specific action to calendar event.  This requires setting up $CFG-&amp;gt;calendar and include external calendar file in $CFG-&amp;gt;dirroot .&#039;/calendar/&#039;. $CFG-&amp;gt;calendar .&#039;/lib.php&#039;).&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_event_hook($action, array $args)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
List of function for calendar and calendar_event.&lt;br /&gt;
&lt;br /&gt;
===Retrieve or print calendar&#039;s information===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_get_default_courses()&lt;br /&gt;
calendar_get_days()&lt;br /&gt;
calendar_get_starting_weekday()&lt;br /&gt;
calendar_day_representation($tstamp, $now = false, $usecommonwords = true)&lt;br /&gt;
calendar_time_representation($time)&lt;br /&gt;
calendar_wday_name($englishname)&lt;br /&gt;
calendar_days_in_month($month, $year)&lt;br /&gt;
calendar_get_link_href($linkbase, $d, $m, $y)&lt;br /&gt;
calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_year = false)&lt;br /&gt;
calendar_get_popup($is_today, $event_timestart, $popupcontent = &#039;&#039;) &lt;br /&gt;
calendar_add_month($month, $year)&lt;br /&gt;
calendar_sub_month($month, $year)&lt;br /&gt;
calendar_get_module_cached(&amp;amp;$coursecache, $modulename, $instance) &lt;br /&gt;
calendar_get_course_cached(&amp;amp;$coursecache, $courseid)&lt;br /&gt;
calendar_print_month_selector($name, $selected)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Control calendar display===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_top_controls($type, $data)&lt;br /&gt;
calendar_filter_controls(moodle_url $returnurl)&lt;br /&gt;
calendar_preferences_button(stdClass $course)&lt;br /&gt;
calendar_set_filters(array $courseeventsfrom, $ignorefilters = false)&lt;br /&gt;
calendar_get_link_previous($text, $linkbase, $d, $m, $y, $accesshide = false)&lt;br /&gt;
calendar_get_link_next($text, $linkbase, $d, $m, $y, $accesshide = false)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Retrieve calendar_event information===&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
calendar_get_allowed_types(&amp;amp;$allowed, $course = null)&lt;br /&gt;
calendar_add_event_allowed($event) &lt;br /&gt;
calendar_edit_event_allowed($event)&lt;br /&gt;
calendar_user_can_add_event($course)&lt;br /&gt;
calendar_show_event_type($type, $user = null)&lt;br /&gt;
calendar_set_event_type_display($type, $display = null, $user = null)&lt;br /&gt;
calendar_get_events($tstart, $tend, $users, $groups, $courses, $withduration = true, $ignorehidden = true)&lt;br /&gt;
calendar_events_by_day($events, $month, $year, &amp;amp;$eventsbyday, &amp;amp;$durationbyday, &amp;amp;$typesbyday, &amp;amp;$courses) &lt;br /&gt;
calendar_get_upcoming($courses, $groups, $users, $daysinfuture, $maxevents, $fromtime = 0)&lt;br /&gt;
calendar_get_block_upcoming($events, $linkhref = NULL)&lt;br /&gt;
calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime = 0)&lt;br /&gt;
calendar_add_event_metadata($event)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
The following are examples of using the basic calendar_event API in Moodle.&lt;br /&gt;
&lt;br /&gt;
===Example to create new event===&lt;br /&gt;
Creating new calendar event for closing feedback date.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$event = new stdClass;&lt;br /&gt;
$event-&amp;gt;name         = get_string(&#039;stop&#039;, &#039;feedback&#039;).&#039; &#039;.$feedback-&amp;gt;name;&lt;br /&gt;
$event-&amp;gt;description  = format_module_intro(&#039;feedback&#039;, $feedback, $feedback-&amp;gt;coursemodule);&lt;br /&gt;
$event-&amp;gt;courseid     = $feedback-&amp;gt;course;&lt;br /&gt;
$event-&amp;gt;groupid      = 0;&lt;br /&gt;
$event-&amp;gt;userid       = 0;&lt;br /&gt;
$event-&amp;gt;modulename   = &#039;feedback&#039;;&lt;br /&gt;
$event-&amp;gt;instance     = $feedback-&amp;gt;id;&lt;br /&gt;
$event-&amp;gt;eventtype    = &#039;feedbackcloses&#039;; // For activity module&#039;s events, this can be used to set the alternative text of the event icon. Set it to &#039;pluginname&#039; unless you have a better string.&lt;br /&gt;
$event-&amp;gt;timestart    = $feedback-&amp;gt;timeclose;&lt;br /&gt;
$event-&amp;gt;visible      = instance_is_visible(&#039;feedback&#039;, $feedback);&lt;br /&gt;
$event-&amp;gt;timeduration = 0;&lt;br /&gt;
&lt;br /&gt;
calendar_event::create($event);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Updating existing calendar event===&lt;br /&gt;
Simple example of updating exiting event through moodle form.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
&lt;br /&gt;
$data = $mform-&amp;gt;get_data();&lt;br /&gt;
$event-&amp;gt;update($data);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Deleting existing calendar event===&lt;br /&gt;
Simple example of deleting existing event from database.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$eventid = required_param(&#039;id&#039;, PARAM_INT);&lt;br /&gt;
$event = calendar_event::load($eventid);&lt;br /&gt;
$event-&amp;gt;delete($repeats);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
* [[:en:Calendar|Calendar user docs]]&lt;br /&gt;
* [[Calendar types]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51879</id>
		<title>GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51879"/>
		<updated>2017-02-14T04:08:23Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Atto image resize/crop/rotate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The outputs of the Moodle GSOC 2016 projects were summarised at [https://moodle.com/2016/10/12/moodle-continues-to-advance-open-source-project-through-googles-summer-of-code/ moodle.com blog post].&lt;br /&gt;
&lt;br /&gt;
For more details, see the [https://dev.moodle.org/course/view.php?id=23 GSOC 2016 course] at dev.moodle.org.&lt;br /&gt;
&lt;br /&gt;
The final projects were also presented at the [[Developer meeting September 2016]] - see [http://recordings.blindsidenetworks.com/moodlehq/c51f7a86bf8c2f31dba5c5a454a6fd349674f9c2-1473335743561/capture the meeting video archive].&lt;br /&gt;
&lt;br /&gt;
== Plugin skeleton generator ==&lt;br /&gt;
&lt;br /&gt;
The project’s aim was to make developing plugins a much easier task. A new tool was designed and implemented by the GSOC student. Based on coding techniques used by existing plugins, on the guides and specifications found in the Moodle developer documentation, as well as on the user’s input, the new tool generates skeleton code that can be used to build new Moodle plugins.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Moodle plugin accepted into the Moodle Plugins directory: https://moodle.org/plugins/tool_pluginskel&lt;br /&gt;
* Documentation: [[:en:Plugin skeleton generator|Plugin skeleton generator docs page]]&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2024009 Alexandru Elisei]&lt;br /&gt;
* Mentor: [https://moodle.org/user/view.php?id=1601 David Mudrák]&lt;br /&gt;
* Detailed project spec page: [[tool_pluginkenobi]]&lt;br /&gt;
&lt;br /&gt;
==Adding search to more Moodle components==&lt;br /&gt;
&lt;br /&gt;
Several key search areas like users or messages have been successfully integrated into Moodle&#039;s core expanding global search subsystem&#039;s functionality to cover all major search use cases. You can see the full list of issues in this [https://tracker.moodle.org/browse/MDL-55538 epic].&lt;br /&gt;
 &lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Integrated into Moodle&#039;s core&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2039167&amp;amp;course=5 Devang Gaur]&lt;br /&gt;
* Mentor: [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
* Issues: [https://tracker.moodle.org/browse/MDL-55538 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Atto image resize/crop/rotate==&lt;br /&gt;
With the current code users can resize, crop and rotate images in the atto text editor in the same way this can be achieved in Google docs.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Getting ready for integration review&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=1953983 Joey Andres]&lt;br /&gt;
* Mentor: [https://moodle.org/user/profile.php?id=1057750 Mark Nelson]&lt;br /&gt;
* Issues: [https://tracker.moodle.org/browse/MDL-44239 Moodle tracker issue] and [https://tracker.moodle.org/browse/MDL-55633 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Add support to end-to-end testing in the Mobile app==&lt;br /&gt;
&lt;br /&gt;
The project&#039;s aim was to add more end to end tests to the Mobile application. Supun developed almost 30 new tests that were integrated into Moodle Mobile.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Almost 30 new tests integrated into Moodle Mobile&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;
* [https://github.com/Supun94/moodlemobile2/commits/gsoc-e2e Original branch with the new tests]&lt;br /&gt;
* Related issues: MOBILE-1864 AND MOBILE-1179&lt;br /&gt;
* [http://blog.supun.me/2016/08/19/gsoc-2016-final-protractor-test-implementation-documentation-moodle-mobile-app/ Detailed project documentation]&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>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51878</id>
		<title>GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51878"/>
		<updated>2017-02-14T04:07:54Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Atto image resize/crop/rotate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The outputs of the Moodle GSOC 2016 projects were summarised at [https://moodle.com/2016/10/12/moodle-continues-to-advance-open-source-project-through-googles-summer-of-code/ moodle.com blog post].&lt;br /&gt;
&lt;br /&gt;
For more details, see the [https://dev.moodle.org/course/view.php?id=23 GSOC 2016 course] at dev.moodle.org.&lt;br /&gt;
&lt;br /&gt;
The final projects were also presented at the [[Developer meeting September 2016]] - see [http://recordings.blindsidenetworks.com/moodlehq/c51f7a86bf8c2f31dba5c5a454a6fd349674f9c2-1473335743561/capture the meeting video archive].&lt;br /&gt;
&lt;br /&gt;
== Plugin skeleton generator ==&lt;br /&gt;
&lt;br /&gt;
The project’s aim was to make developing plugins a much easier task. A new tool was designed and implemented by the GSOC student. Based on coding techniques used by existing plugins, on the guides and specifications found in the Moodle developer documentation, as well as on the user’s input, the new tool generates skeleton code that can be used to build new Moodle plugins.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Moodle plugin accepted into the Moodle Plugins directory: https://moodle.org/plugins/tool_pluginskel&lt;br /&gt;
* Documentation: [[:en:Plugin skeleton generator|Plugin skeleton generator docs page]]&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2024009 Alexandru Elisei]&lt;br /&gt;
* Mentor: [https://moodle.org/user/view.php?id=1601 David Mudrák]&lt;br /&gt;
* Detailed project spec page: [[tool_pluginkenobi]]&lt;br /&gt;
&lt;br /&gt;
==Adding search to more Moodle components==&lt;br /&gt;
&lt;br /&gt;
Several key search areas like users or messages have been successfully integrated into Moodle&#039;s core expanding global search subsystem&#039;s functionality to cover all major search use cases. You can see the full list of issues in this [https://tracker.moodle.org/browse/MDL-55538 epic].&lt;br /&gt;
 &lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Integrated into Moodle&#039;s core&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2039167&amp;amp;course=5 Devang Gaur]&lt;br /&gt;
* Mentor: [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
* Issues: [https://tracker.moodle.org/browse/MDL-55538 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Atto image resize/crop/rotate==&lt;br /&gt;
With the current code users can resize, crop and rotate images in the atto text edit in the same way this can be achieved in Google docs.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Getting ready for integration review&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=1953983 Joey Andres]&lt;br /&gt;
* Mentor: [https://moodle.org/user/profile.php?id=1057750 Mark Nelson]&lt;br /&gt;
* Issues: [https://tracker.moodle.org/browse/MDL-44239 Moodle tracker issue] and [https://tracker.moodle.org/browse/MDL-55633 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Add support to end-to-end testing in the Mobile app==&lt;br /&gt;
&lt;br /&gt;
The project&#039;s aim was to add more end to end tests to the Mobile application. Supun developed almost 30 new tests that were integrated into Moodle Mobile.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Almost 30 new tests integrated into Moodle Mobile&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;
* [https://github.com/Supun94/moodlemobile2/commits/gsoc-e2e Original branch with the new tests]&lt;br /&gt;
* Related issues: MOBILE-1864 AND MOBILE-1179&lt;br /&gt;
* [http://blog.supun.me/2016/08/19/gsoc-2016-final-protractor-test-implementation-documentation-moodle-mobile-app/ Detailed project documentation]&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>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51877</id>
		<title>GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51877"/>
		<updated>2017-02-14T04:07:20Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Atto image resize/crop/rotate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The outputs of the Moodle GSOC 2016 projects were summarised at [https://moodle.com/2016/10/12/moodle-continues-to-advance-open-source-project-through-googles-summer-of-code/ moodle.com blog post].&lt;br /&gt;
&lt;br /&gt;
For more details, see the [https://dev.moodle.org/course/view.php?id=23 GSOC 2016 course] at dev.moodle.org.&lt;br /&gt;
&lt;br /&gt;
The final projects were also presented at the [[Developer meeting September 2016]] - see [http://recordings.blindsidenetworks.com/moodlehq/c51f7a86bf8c2f31dba5c5a454a6fd349674f9c2-1473335743561/capture the meeting video archive].&lt;br /&gt;
&lt;br /&gt;
== Plugin skeleton generator ==&lt;br /&gt;
&lt;br /&gt;
The project’s aim was to make developing plugins a much easier task. A new tool was designed and implemented by the GSOC student. Based on coding techniques used by existing plugins, on the guides and specifications found in the Moodle developer documentation, as well as on the user’s input, the new tool generates skeleton code that can be used to build new Moodle plugins.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Moodle plugin accepted into the Moodle Plugins directory: https://moodle.org/plugins/tool_pluginskel&lt;br /&gt;
* Documentation: [[:en:Plugin skeleton generator|Plugin skeleton generator docs page]]&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2024009 Alexandru Elisei]&lt;br /&gt;
* Mentor: [https://moodle.org/user/view.php?id=1601 David Mudrák]&lt;br /&gt;
* Detailed project spec page: [[tool_pluginkenobi]]&lt;br /&gt;
&lt;br /&gt;
==Adding search to more Moodle components==&lt;br /&gt;
&lt;br /&gt;
Several key search areas like users or messages have been successfully integrated into Moodle&#039;s core expanding global search subsystem&#039;s functionality to cover all major search use cases. You can see the full list of issues in this [https://tracker.moodle.org/browse/MDL-55538 epic].&lt;br /&gt;
 &lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Integrated into Moodle&#039;s core&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2039167&amp;amp;course=5 Devang Gaur]&lt;br /&gt;
* Mentor: [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
* Issues: [https://tracker.moodle.org/browse/MDL-55538 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Atto image resize/crop/rotate==&lt;br /&gt;
With the current code users can resize, crop and rotate images in the atto text edit in the same way this can be achieved in Google docs.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Getting ready for integration review&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=1953983&amp;amp;course=5 Joey Andres]&lt;br /&gt;
* Mentor: [https://moodle.org/user/profile.php?id=1057750 Mark Nelson]&lt;br /&gt;
* Issues: [https://tracker.moodle.org/browse/MDL-44239 Moodle tracker issue] and [https://tracker.moodle.org/browse/MDL-55633 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Add support to end-to-end testing in the Mobile app==&lt;br /&gt;
&lt;br /&gt;
The project&#039;s aim was to add more end to end tests to the Mobile application. Supun developed almost 30 new tests that were integrated into Moodle Mobile.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Almost 30 new tests integrated into Moodle Mobile&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;
* [https://github.com/Supun94/moodlemobile2/commits/gsoc-e2e Original branch with the new tests]&lt;br /&gt;
* Related issues: MOBILE-1864 AND MOBILE-1179&lt;br /&gt;
* [http://blog.supun.me/2016/08/19/gsoc-2016-final-protractor-test-implementation-documentation-moodle-mobile-app/ Detailed project documentation]&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>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51876</id>
		<title>GSOC/2016</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=GSOC/2016&amp;diff=51876"/>
		<updated>2017-02-14T04:06:11Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Atto image resize/crop/rotate */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The outputs of the Moodle GSOC 2016 projects were summarised at [https://moodle.com/2016/10/12/moodle-continues-to-advance-open-source-project-through-googles-summer-of-code/ moodle.com blog post].&lt;br /&gt;
&lt;br /&gt;
For more details, see the [https://dev.moodle.org/course/view.php?id=23 GSOC 2016 course] at dev.moodle.org.&lt;br /&gt;
&lt;br /&gt;
The final projects were also presented at the [[Developer meeting September 2016]] - see [http://recordings.blindsidenetworks.com/moodlehq/c51f7a86bf8c2f31dba5c5a454a6fd349674f9c2-1473335743561/capture the meeting video archive].&lt;br /&gt;
&lt;br /&gt;
== Plugin skeleton generator ==&lt;br /&gt;
&lt;br /&gt;
The project’s aim was to make developing plugins a much easier task. A new tool was designed and implemented by the GSOC student. Based on coding techniques used by existing plugins, on the guides and specifications found in the Moodle developer documentation, as well as on the user’s input, the new tool generates skeleton code that can be used to build new Moodle plugins.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Moodle plugin accepted into the Moodle Plugins directory: https://moodle.org/plugins/tool_pluginskel&lt;br /&gt;
* Documentation: [[:en:Plugin skeleton generator|Plugin skeleton generator docs page]]&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2024009 Alexandru Elisei]&lt;br /&gt;
* Mentor: [https://moodle.org/user/view.php?id=1601 David Mudrák]&lt;br /&gt;
* Detailed project spec page: [[tool_pluginkenobi]]&lt;br /&gt;
&lt;br /&gt;
==Adding search to more Moodle components==&lt;br /&gt;
&lt;br /&gt;
Several key search areas like users or messages have been successfully integrated into Moodle&#039;s core expanding global search subsystem&#039;s functionality to cover all major search use cases. You can see the full list of issues in this [https://tracker.moodle.org/browse/MDL-55538 epic].&lt;br /&gt;
 &lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Integrated into Moodle&#039;s core&lt;br /&gt;
* Student: [https://moodle.org/user/view.php?id=2039167&amp;amp;course=5 Devang Gaur]&lt;br /&gt;
* Mentor: [https://moodle.org/user/profile.php?id=122326 David Monllaó]&lt;br /&gt;
* Issues: [https://tracker.moodle.org/browse/MDL-55538 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Atto image resize/crop/rotate==&lt;br /&gt;
With the current code users can resize, crop and rotate images in the atto text edit in the same way this can be achieved in Google docs.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Getting ready for integration review&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;
* Issues: [https://tracker.moodle.org/browse/MDL-44239 Moodle tracker issue] and [https://tracker.moodle.org/browse/MDL-55633 Moodle tracker issue]&lt;br /&gt;
&lt;br /&gt;
==Add support to end-to-end testing in the Mobile app==&lt;br /&gt;
&lt;br /&gt;
The project&#039;s aim was to add more end to end tests to the Mobile application. Supun developed almost 30 new tests that were integrated into Moodle Mobile.&lt;br /&gt;
&lt;br /&gt;
* Project status: Successfully passed&lt;br /&gt;
* Project output: Almost 30 new tests integrated into Moodle Mobile&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;
* [https://github.com/Supun94/moodlemobile2/commits/gsoc-e2e Original branch with the new tests]&lt;br /&gt;
* Related issues: MOBILE-1864 AND MOBILE-1179&lt;br /&gt;
* [http://blog.supun.me/2016/08/19/gsoc-2016-final-protractor-test-implementation-documentation-moodle-mobile-app/ Detailed project documentation]&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>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=51796</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=51796"/>
		<updated>2017-01-30T08:02:25Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Potential projects */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
&lt;br /&gt;
When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you complete the [http://dev.moodle.org/course/view.php?id=2 Introduction to Moodle Programming] course on [http://dev.moodle.org/ dev.moodle.org]. To access this you will need to have an account on moodle.org first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer]&#039;&#039;. See the [https://moodle.org/mod/forum/discuss.php?d=260354 Plugins adoption programme].&lt;br /&gt;
&lt;br /&gt;
As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Pusher integration for HTML5 push notifications ===&lt;br /&gt;
Moodle supports message output plugins. By adding a plugin for pusher.com and a Javascript service worker to listen for push notifications, we can have realtime HTML5 notifications on all platforms.&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: Javascript (JQuery, AMD), PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=1337843 Damyon Wiese]&lt;br /&gt;
&lt;br /&gt;
=== Improve Behat tests in SCORM plugin ===&lt;br /&gt;
The Moodle SCORM plugin does not contain very many behat tests and most tests are manual. The Claude Ostyn diagnostic SCO should be used to implement a range of new Behat tests to cover the functionality that the SCORM module provides.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Behat tests for all existing SCORM QA tests (where possible)&lt;br /&gt;
* Behat tests for all SCORM settings (eg standards mode, mastery score settings etc) &lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid.&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Advanced Grading in Forums ===&lt;br /&gt;
Finish the work required to add the advanced grading feature to the Moodle forum activity. This builds on some existing work available at MDL-31860&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Modify the forum grading so that it pushes 2 grade areas (or 3 including ratings) into the gradebook instead of a single grade.&lt;br /&gt;
* Improve interface that allows overall forum participation grading.&lt;br /&gt;
* Behat tests for all new functionality.&lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Add support to end-to-end testing in the Mobile app ===&lt;br /&gt;
&lt;br /&gt;
[https://angular.github.io/protractor/#/ Protractor] is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.&lt;br /&gt;
&lt;br /&gt;
The basements for this project are done, see MOBILE-1179, the only remaining work is to add more tests to the app and document the set-up process in the Moodle developers wiki.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (AngularJS)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
===Clef | Two-Factor Authentication===&lt;br /&gt;
Create [https://getclef.com Clef two factor authentication] plugin, so  a user can log in using their mobile to reduce login time. This will improve security and reduce  the login time for users.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP, Javascript&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=1328988 Rajesh Taneja]&lt;br /&gt;
&lt;br /&gt;
=== Multi-step login screen ===&lt;br /&gt;
Update the login screen to first ask for a username, and then the password as a two-step process.&lt;br /&gt;
See the login process for Google&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP, JavaScript, Mustache&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=1779959 John Okely]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== 2FA - Two Factor Authentication ===&lt;br /&gt;
Add support for Two-Factor Authentication. This would work well when combined with the Multi-step login screen.&lt;br /&gt;
Factors requiring consideration include the Mobile app integrations.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP, JavaScript, Mustache&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=268794 Andrew Nicols]&lt;br /&gt;
&lt;br /&gt;
=== CLI Helper for Moodle Developers ===&lt;br /&gt;
Possibly an addendum to MDK, a set of scripts to help facilitate various common tasks. In particular:&lt;br /&gt;
* creation of Persistent Objects including their Class files, the XMLDB code to create their tables, and the XMLDB upgrade scripts required to upgrade (including version bumps)&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP, Python?&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Hard&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=268794 Andrew Nicols]&lt;br /&gt;
&lt;br /&gt;
=== Trait for Mock DB in unit tests ===&lt;br /&gt;
In moodle we run every unit test using a real database. This is extremely slow with little benefit. Granted it does catch some cross-database compatibility issues, but we don&#039;t need it for every test. We should add a trait that test classes can use that will automatically set up mock $DB to save processing power and unnecessary waiting for DB.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP, PHPUnit&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Easy&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=268794 Andrew Nicols] or [https://moodle.org/user/profile.php?id=1779959 John Okely]&lt;br /&gt;
&lt;br /&gt;
=== Mock implementation of DML ===&lt;br /&gt;
In moodle we run every unit test using a real database. This is extremely slow with little benefit. Granted it does catch some cross-database compatibility issues, but we don&#039;t need it for every test. It is possible to extend moodle_database and mock all the calls to use an in memory/mocked database. The easiest way to do this may be to use first make a Data Access Object implementation, and then use a mock DAO&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP, PHPUnit&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Very Hard&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=1779959 John Okely]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;br /&gt;
* [[Projects for new developers/Archive|Archive]] of outdated and/or inactive calls for projects&lt;br /&gt;
* [https://docs.moodle.org/dev/Moodle_Wishlist a Wishlist] by some Moodle users. Some of the good ideas here may be adopted.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51641</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51641"/>
		<updated>2016-12-19T04:46:25Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Course Completion Tracking */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
** User the todo api javascript module to interact with the server external API&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
*** action state - Has this been actioned? Eg, The assignment was submitted.&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
* Add a javascript module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
* Make sure we are only displaying appropriate events (ie. if there is a user override then show that for the user, not multiple).&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
==== Notes ====&lt;br /&gt;
There are different ways of calculating the completion percentage for a course and some will be more informative than others, depending on the type of usage of the course.&lt;br /&gt;
&lt;br /&gt;
Some possible options are:&lt;br /&gt;
* The number of completed+visible activities / The number of visible activities&lt;br /&gt;
* The number of completed activities / The number of activities&lt;br /&gt;
* The current week / the number of weeks&lt;br /&gt;
* The (current date - course start date) / (course end date - course start date) * Requires a course end date&lt;br /&gt;
* The current course grade / the required course grade (don’t expose hidden grades)&lt;br /&gt;
* The enrolment duration / the required enrolment duration&lt;br /&gt;
&lt;br /&gt;
Because each course completion criteria requires a different calculation, one possible method is:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;If course completion is enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
for each course completion criteria - get the current and total possible values for completion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;if all are required:&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
normalise and sum/average the values&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;if any is required&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
calculate the highest percentage completion&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;If only activity completion is enabled (and not course completion)&#039;&#039;&#039; &lt;br /&gt;
&lt;br /&gt;
calculate the completion percentage purely on the number of activities complete / the total number of activities. (Ignoring activities with no completion - should we ignore activities the current user cannot see via access restrictions?)&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;If course completion is not enabled&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Try and calculation the completion based purely on the course start / end date&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;To calculate the current and total values for each completion criteria:&#039;&#039;&#039;&lt;br /&gt;
* Activity completion - number of activities complete / number of activities required to be completed&lt;br /&gt;
* Completion of other courses - number of courses complete / number of courses required to be completed&lt;br /&gt;
* Enrolment Date - the current date - course start date / the enrolled until date - course start date. If there is no course start date use the enrolment start date. Max of 1.&lt;br /&gt;
* Enroled duration - the number of days enrolled / the number of days required to be enrolled. Max of 1.&lt;br /&gt;
* Unenrollment. 0 if enrolled, 1 if unenrolled.&lt;br /&gt;
* Course grade - current course grade / required course grade. Max of 1.&lt;br /&gt;
* Manual self completion. 0 if not complete, 1 if complete&lt;br /&gt;
* Manual completion by others. 0 if not complete, 1 if complete&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
=== Proof Of Concept Code ===&lt;br /&gt;
I&#039;ve knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2&lt;br /&gt;
&lt;br /&gt;
Please review it and add any comments or what ever.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
** Answer: It gets removed.&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;br /&gt;
* When an activity combines both a &#039;&#039;due date&#039;&#039; and an &#039;&#039;expected completed on&#039;&#039; date (e.g. assignment module with completion), what is the date of the task?&lt;br /&gt;
* Are activities the only ones that generate calendar events (todos)?&lt;br /&gt;
&lt;br /&gt;
== Questions for the Integrators ==&lt;br /&gt;
* What should we do with the existing block_course_overview block and the corresponding hooks in the activities (eg. xxx_print_overview())?&lt;br /&gt;
# Leave the block and keep the hooks.&lt;br /&gt;
## Have to maintain more code. This is not desirable as we have a new fancy block now.&lt;br /&gt;
# Leave the block in the code and deprecate the hooks in the activities.&lt;br /&gt;
## Will be odd having a block in core we know will display debugging messages. &lt;br /&gt;
# Delete the block and don&#039;t put it in plugins DB and remove the hooks from the activities completely, no debugging messages or anything.&lt;br /&gt;
## This will break for users who are relying on the code being there, or third party activities who have extensive code in their hook to display something fancy that no longer gets used.&lt;br /&gt;
# We should move the block to the plugins DB and deprecate the hooks.&lt;br /&gt;
## It is odd having a block in the plugins DB that when installed will display debugging messages.&lt;br /&gt;
# We should ask Integrators.&lt;br /&gt;
&lt;br /&gt;
== Things for Damyon ==&lt;br /&gt;
* Think of complex scenarios that the API will have to deal with. If it&#039;s too complex forget Damyon mentioned it.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51574</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51574"/>
		<updated>2016-12-13T06:04:59Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
** User the todo api javascript module to interact with the server external API&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
*** action state - Has this been actioned? Eg, The assignment was submitted.&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
* Add a javascript module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
* Make sure we are only displaying appropriate events (ie. if there is a user override then show that for the user, not multiple).&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
=== Proof Of Concept Code ===&lt;br /&gt;
I&#039;ve knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2&lt;br /&gt;
&lt;br /&gt;
Please review it and add any comments or what ever.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
** Answer: It gets removed.&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;br /&gt;
* When an activity combines both a &#039;&#039;due date&#039;&#039; and an &#039;&#039;expected completed on&#039;&#039; date (e.g. assignment module with completion), what is the date of the task?&lt;br /&gt;
* Are activities the only ones that generate calendar events (todos)?&lt;br /&gt;
&lt;br /&gt;
== Questions for the Integrators ==&lt;br /&gt;
* What should we do with the existing block_course_overview block and the corresponding hooks in the activities (eg. xxx_print_overview())?&lt;br /&gt;
# Leave the block and keep the hooks.&lt;br /&gt;
## Have to maintain more code. This is not desirable as we have a new fancy block now.&lt;br /&gt;
# Leave the block in the code and deprecate the hooks in the activities.&lt;br /&gt;
## Will be odd having a block in core we know will display debugging messages. &lt;br /&gt;
# Delete the block and don&#039;t put it in plugins DB and remove the hooks from the activities completely, no debugging messages or anything.&lt;br /&gt;
## This will break for users who are relying on the code being there, or third party activities who have extensive code in their hook to display something fancy that no longer gets used.&lt;br /&gt;
# We should move the block to the plugins DB and deprecate the hooks.&lt;br /&gt;
## It is odd having a block in the plugins DB that when installed will display debugging messages.&lt;br /&gt;
# We should ask Integrators.&lt;br /&gt;
&lt;br /&gt;
== Things for Damyon ==&lt;br /&gt;
* Think of complex scenarios that the API will have to deal with. If it&#039;s too complex forget Damyon mentioned it.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51573</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51573"/>
		<updated>2016-12-13T05:44:47Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Questions for the Integrators */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
** User the todo api javascript module to interact with the server external API&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
*** action state - Has this been actioned? Eg, The assignment was submitted.&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
* Add a javascript module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
=== Proof Of Concept Code ===&lt;br /&gt;
I&#039;ve knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2&lt;br /&gt;
&lt;br /&gt;
Please review it and add any comments or what ever.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
** Answer: It gets removed.&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;br /&gt;
* When an activity combines both a &#039;&#039;due date&#039;&#039; and an &#039;&#039;expected completed on&#039;&#039; date (e.g. assignment module with completion), what is the date of the task?&lt;br /&gt;
&lt;br /&gt;
== Questions for the Integrators ==&lt;br /&gt;
* What should we do with the existing block_course_overview block and the corresponding hooks in the activities (eg. xxx_print_overview())?&lt;br /&gt;
# Leave the block and keep the hooks.&lt;br /&gt;
## Have to maintain more code. This is not desirable as we have a new fancy block now.&lt;br /&gt;
# Leave the block in the code and deprecate the hooks in the activities.&lt;br /&gt;
## Will be odd having a block in core we know will display debugging messages. &lt;br /&gt;
# Delete the block and don&#039;t put it in plugins DB and remove the hooks from the activities completely, no debugging messages or anything.&lt;br /&gt;
## This will break for users who are relying on the code being there, or third party activities who have extensive code in their hook to display something fancy that no longer gets used.&lt;br /&gt;
# We should move the block to the plugins DB and deprecate the hooks.&lt;br /&gt;
## It is odd having a block in the plugins DB that when installed will display debugging messages.&lt;br /&gt;
# We should ask integrators.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51572</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51572"/>
		<updated>2016-12-13T05:43:33Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Questions for the Integrators */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
** User the todo api javascript module to interact with the server external API&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
*** action state - Has this been actioned? Eg, The assignment was submitted.&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
* Add a javascript module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
=== Proof Of Concept Code ===&lt;br /&gt;
I&#039;ve knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2&lt;br /&gt;
&lt;br /&gt;
Please review it and add any comments or what ever.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
** Answer: It gets removed.&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;br /&gt;
* When an activity combines both a &#039;&#039;due date&#039;&#039; and an &#039;&#039;expected completed on&#039;&#039; date (e.g. assignment module with completion), what is the date of the task?&lt;br /&gt;
&lt;br /&gt;
== Questions for the Integrators ==&lt;br /&gt;
* What should we do with the existing block_course_overview block?&lt;br /&gt;
# Leave the block and keep the hooks.&lt;br /&gt;
## Have to maintain more code. This is not desirable as we have a new fancy block now.&lt;br /&gt;
# Leave the block in the code and deprecate the hooks in the activities.&lt;br /&gt;
## Will be odd having a block in core we know will display debugging messages. &lt;br /&gt;
# Delete the block and don&#039;t put it in plugins DB and remove the hooks from the activities completely, no debugging messages or anything.&lt;br /&gt;
## This will break for users who are relying on the code being there, or third party activities who have extensive code in their hook to display something fancy that no longer gets used.&lt;br /&gt;
# We should move the block to the plugins DB and deprecate the hooks.&lt;br /&gt;
## It is odd having a block in the plugins DB that when installed will display debugging messages.&lt;br /&gt;
# We should ask integrators.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51571</id>
		<title>My course overview improvements</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=My_course_overview_improvements&amp;diff=51571"/>
		<updated>2016-12-13T05:41:42Z</updated>

		<summary type="html">&lt;p&gt;Markn: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This page will detail the technical specification for the improvements to the My course overview block.&lt;br /&gt;
&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Improvements to my course overview block.&lt;br /&gt;
|state = Starting&lt;br /&gt;
|tracker = MDL-55611&lt;br /&gt;
|discussion = https://tracker.moodle.org/browse/UX-8&lt;br /&gt;
|assignee = HQ Projects Team&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Summary ==&lt;br /&gt;
&lt;br /&gt;
The new design for the UI for the course overview block requires the ability for Moodle to efficiently query plugins for a list of &amp;quot;date based&amp;quot; tasks for the current user.&lt;br /&gt;
&lt;br /&gt;
The existing &amp;quot;mod print_overview&amp;quot; callbacks do not have sufficient functionality (no separation of fields, inefficient, incomplete, no relation to completion API, inconsistently implemented across modules) so we will have to build a new API (and deprecate mod_xx_print_overview). &lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
&lt;br /&gt;
=== Course Overview Block ===&lt;br /&gt;
The course overview block will communicate exclusively with the Todo API and will present the Todo&#039;s as described in UX-8. We need to remove the old code used to render the course overview block and have it use the new APIs.&lt;br /&gt;
&lt;br /&gt;
* Mustache templates:&lt;br /&gt;
** General template for the block (wrapping template)&lt;br /&gt;
*** Timeline view&lt;br /&gt;
**** Sort by dates (wrapping template)&lt;br /&gt;
***** Template for displaying single todo (rendered in list)&lt;br /&gt;
**** Sort by courses (wrapping template)&lt;br /&gt;
***** Single course section, includes list of todos similar to &amp;quot;sort by dates&amp;quot; (can maybe re-use the template for a single todo here)&lt;br /&gt;
** Courses view&lt;br /&gt;
*** Single template can probably be re-used for &amp;quot;in progress&amp;quot;, &amp;quot;upcoming&amp;quot; and &amp;quot;completed&amp;quot; views, just rendered with different data&lt;br /&gt;
*** As above, single template for a course&lt;br /&gt;
* Javascript&lt;br /&gt;
** Module for the course overview block that handles the high level interaction (changing between timeline and courses views etc)&lt;br /&gt;
** Module for timeline view (maybe even have separate modules for &amp;quot;sort by dates&amp;quot; and &amp;quot;sort by courses&amp;quot;?). Handles requesting the data and rendering the templates etc.&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Module for courses view that handles requesting the data and rendering the templates&lt;br /&gt;
*** Module needs to handle paginated results (view more button being clicked)&lt;br /&gt;
** Use the new pie chart we add&lt;br /&gt;
** User the todo api javascript module to interact with the server external API&lt;br /&gt;
* CSS: Style each of the templates (try to re-use the Bootstrap classes to keep this minimal)&lt;br /&gt;
** Style Boost theme&lt;br /&gt;
** Style bootstrap base theme (e.g. clean)&lt;br /&gt;
** Add responsive styling (need to ask the UX team for some mock ups of smaller resolutions)&lt;br /&gt;
* Accessibility: Add the appropriate aria attributes to each of the templates above to make the block accessible by a screen reader (more work than it seems)&lt;br /&gt;
* Update blocks/course_overview/block_course_overview.php &amp;quot;get_content&amp;quot; to render a template via the renderer (need to add a new function)&lt;br /&gt;
* Remove the existing functions being used to render the course overview (including functions in the renderer and lib.php)&lt;br /&gt;
* Add behat tests for the interface that covers each permutation of the view (timeline, sort by dates, courses, courseview etc)&lt;br /&gt;
&lt;br /&gt;
=== Todo API ===&lt;br /&gt;
This will be a new API in core to represent the concept of &amp;quot;todos&amp;quot; in Moodle, i.e. the list of items displayed in the course overview block. A todo is made up of a calendar event and an associated action for the user. &lt;br /&gt;
&lt;br /&gt;
The appropriate action will need to be calculated on a per user basis, per event, and per module because of complex permission problems. E.g. a user may have an event for an assignment that they no longer have permission to view or they may have an event for an assignment that can&#039;t be started until after another module has been completed etc. &lt;br /&gt;
&lt;br /&gt;
Given the intensity of some of these calculations we&#039;ll need to look into aggressively caching results and maybe even avoid doing the calculations per request.&lt;br /&gt;
&lt;br /&gt;
Since we&#039;re leveraging the existing calendar events for the static data we may not need to actually persist the todos anywhere other than caching.&lt;br /&gt;
&lt;br /&gt;
* Add a todo class (pretty please can we have an actual class rather than just stdClass)&lt;br /&gt;
** Some properties of the class:&lt;br /&gt;
*** unique id (context id, component, area and item id?)&lt;br /&gt;
*** name - the name of the thing the todo relates to (e.g. activity name)&lt;br /&gt;
*** url - the url of the thing the todo relates to (e.g. view.php of the module)&lt;br /&gt;
*** user id - the id of the user this todo belong to&lt;br /&gt;
*** course id - the course if that the todo relates to&lt;br /&gt;
*** icon url - the icon for the todo (default to the module icon)&lt;br /&gt;
*** start date (optional) - when the todo starts&lt;br /&gt;
*** end date (optional) - when the todo must be actioned by&lt;br /&gt;
*** item count - how many associated items there are (e.g. 4 unread posts)&lt;br /&gt;
*** action name - display name of the todo (e.g. &amp;quot;submit assignment&amp;quot;)&lt;br /&gt;
*** action url - url of the todo action (e.g. link to the assignment submission page)&lt;br /&gt;
*** action start date - a date after which the todo can be actioned (only display the action url after this date)&lt;br /&gt;
*** action state - Has this been actioned? Eg, The assignment was submitted.&lt;br /&gt;
* Add an API class to provide access to todos (get todos for a user, get todos for a user grouped by course etc).&lt;br /&gt;
** Retrieval of todos needs to suppose pagination (and pagination with filters, e.g. first 10 todos in the next 7 days, second 10 todos in the next 7 days).&lt;br /&gt;
* Add a data access layer that abstracts away all of the SQL so that we don&#039;t have that logic everywhere (ideally).&lt;br /&gt;
** The API class would benefit from this.&lt;br /&gt;
** It can also hide the fact that we&#039;re piggy backing on the calendar events, just in case we want to change that in the future.&lt;br /&gt;
** It can also handle all of the caching&lt;br /&gt;
** Support pagination as above&lt;br /&gt;
* Add a standard interface for plugins to implement which will perform the required calculations and permission checks to generate the correct action based on the given user and event(s).&lt;br /&gt;
** The core todo API can&#039;t (and shouldn&#039;t) know every place that will want to create a todo, so we need to provide a standard way for each plugin to register itself as something that will create a todo and an interface for them to do the data manipulation required.&lt;br /&gt;
* Add an external API class.&lt;br /&gt;
** This class shouldn&#039;t contain any business logic (that all lives in the API class). &lt;br /&gt;
** It needs to do is call into the API class to get the appropriate todos and then create the correct renderables from the todo.&lt;br /&gt;
** All functions should be accessible via ajax. This is the class that the course overview block (and mobile app) will use.&lt;br /&gt;
* Add some renderables for the todo&lt;br /&gt;
** The todos should probably just be renderable / template-able themselves&lt;br /&gt;
** These will be used by the external API class.&lt;br /&gt;
* Improve performance using caching (this will be trial and error with the performance testing)&lt;br /&gt;
* Write unit tests for all new API functions and external API functions&lt;br /&gt;
* Add a javascript module to interact with the Todo API (no bespoke ajax requests everywhere please)&lt;br /&gt;
&lt;br /&gt;
=== Chart.js ===&lt;br /&gt;
* Add a new chart type (pie chart) to Moodle&#039;s chart API for use in the templates above&lt;br /&gt;
&lt;br /&gt;
=== Calendar Event API ===&lt;br /&gt;
We&#039;ll be using the existing calendar events as the basis for the &amp;quot;todos&amp;quot;. The current calendar event data structure contains most of the data that we&#039;ll need so we&#039;ll leverage that rather than create duplicate data. The API will need to be extended in order to support the more complex data requests we&#039;ll need.&lt;br /&gt;
&lt;br /&gt;
* Add a display/order by date field to the calendar event table to allow us to do the date sorting (e.g. get me all events in the next 7 days) without having to do the start date + duration calculation&lt;br /&gt;
* Add indexes to the event table if they are missing&lt;br /&gt;
** display/order by date&lt;br /&gt;
** course id&lt;br /&gt;
** user id&lt;br /&gt;
* Add functions to the calendar event API to retrieve groups of events for a given user(s)&lt;br /&gt;
** currently it seems the API only loads one at a time so you need to do direct SQL in the calling code&lt;br /&gt;
** API should probably handle grouping of results, e.g. events for a user would be the distinct set of any course level events + group event override + user event override, where each has higher precedence than the last in the result set&lt;br /&gt;
** API needs to support order by new date field&lt;br /&gt;
** API needs to support limit and offset&lt;br /&gt;
* Add unit tests for new API functions&lt;br /&gt;
&lt;br /&gt;
=== Calendar Block ===&lt;br /&gt;
* Make sure all of the todos are showing up in the calendar for the user&lt;br /&gt;
** Note: we *should* get this for free since we are simply creating calendar events&lt;br /&gt;
&lt;br /&gt;
=== Course Completion Tracking ===&lt;br /&gt;
* Develop a way to track completion on for all courses&lt;br /&gt;
** This needs to take into account all activities within the course, even ones that don&#039;t have any completion tracking enabled&lt;br /&gt;
* Add an API to query the completion status of a course that implements the agreed approach&lt;br /&gt;
* Do we need to persist the course progress somewhere or can it be calculated at run time?&lt;br /&gt;
** Assess performance of both options&lt;br /&gt;
* If we need to persist the completion then we need to add hooks into all places that can alter the completion value and update the persistence so that the data is always accurate&lt;br /&gt;
&lt;br /&gt;
=== General Moodle stuff ===&lt;br /&gt;
* Remove all uses of the &amp;quot;print_overview&amp;quot; callback thingo we&#039;re using through Moodle for modules to add stuff to the course overview block&lt;br /&gt;
* Find all of the places in Moodle that need to generate create a todo and have them create appropriate calendar events&lt;br /&gt;
** A list has been started here https://docs.google.com/document/d/1qfl2MEzdZcNlT2rvBSsIgWhRZsloRnsb2m5TALFn_C8/edit&lt;br /&gt;
* Find all of the places that may affect the status of a calendar event and update the event to make sure it is accurate (eg. editing a module, submitting an assignment, changing course dates etc)&lt;br /&gt;
* Add an implementation of the callback interface thingo to each module that will be creating a todo &lt;br /&gt;
** This implementation will take a calendar event and the user and do all of the appropriate checks to see if the user should see the todo, etc&lt;br /&gt;
** It will then create the appropriate todo from the calendar event and add all of the action stuff.&lt;br /&gt;
&lt;br /&gt;
=== General Testing ===&lt;br /&gt;
* We need to do some performance testing on the overview with a site that has thousands of events and hundreds of courses to ensure that everything renders in a timely manner.&lt;br /&gt;
&lt;br /&gt;
=== Proof Of Concept Code ===&lt;br /&gt;
I&#039;ve knocked together a little proof of concept type branch that does a skeleton implementation of some of this stuff. You can find it here https://github.com/moodle/moodle/compare/e6cb76d...ryanwyllie:todos_poc_2&lt;br /&gt;
&lt;br /&gt;
Please review it and add any comments or what ever.&lt;br /&gt;
&lt;br /&gt;
== Questions for the UX team ==&lt;br /&gt;
* How many items to display in &amp;quot;Next 7 days&amp;quot;? Is there a limit, or we always show all of the items?&lt;br /&gt;
* In the prototype 6c (the one that we are supposed to develop from) the todo disappears from the list when it is actioned. Is this the correct behaviour? What happens to the corresponding event in the calendar? Does that also get removed?&lt;br /&gt;
** Answer: It gets removed.&lt;br /&gt;
* What do we show when a todo is only available for a certain duration? E.g. chat where it&#039;s open for only 3 days. Only having the end date seems weird in that case.&lt;br /&gt;
* Is the list of courses paginated in the courses view? Is there a &amp;quot;More&amp;quot; button to load more courses?&lt;br /&gt;
* What happens with courses which do not have a start date, and end date? Will they show in &amp;quot;In progress&amp;quot; for as long as I am enrolled in them? Note that if I unenrol from the course, I will lose access to it.&lt;br /&gt;
* Are all the three tabs (in progress, upcoming, completed) always shown, even if they are empty?&lt;br /&gt;
* When an activity combines both a &#039;&#039;due date&#039;&#039; and an &#039;&#039;expected completed on&#039;&#039; date (e.g. assignment module with completion), what is the date of the task?&lt;br /&gt;
&lt;br /&gt;
== Questions for the Integrators ==&lt;br /&gt;
* Should we move the block to plugins DB? If we do, then we need to consider the hooks it uses in the activities, should they throw a debugging message? Installing a block you know will throw debugging messages will be odd.&lt;br /&gt;
* Options -&lt;br /&gt;
# Leave the block and keep the hooks.&lt;br /&gt;
## Have to maintain more code. This is not desirable as we have a new fancy block now.&lt;br /&gt;
# Leave the block in the code and deprecate the hooks in the activities.&lt;br /&gt;
## Will be odd having a block in core we know will display debugging messages. &lt;br /&gt;
# Delete the block and don&#039;t put it in plugins DB and remove the hooks from the activities completely, no debugging messages or anything.&lt;br /&gt;
## This will break for users who are relying on the code being there, or third party activities who have extensive code in their hook to display something fancy that no longer gets used.&lt;br /&gt;
# We should move the block to the plugins DB and deprecate the hooks.&lt;br /&gt;
## It is odd having a block in the plugins DB that when installed will display debugging messages.&lt;br /&gt;
# We should ask integrators.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Backup_2.0_for_developers&amp;diff=50828</id>
		<title>Backup 2.0 for developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Backup_2.0_for_developers&amp;diff=50828"/>
		<updated>2016-09-01T08:00:09Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Annotating files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Template:Backup 2.0}}{{Moodle_2.0}}{{Work in progress}}&lt;br /&gt;
&lt;br /&gt;
== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This page tries to explain, from a development perspective, &#039;&#039;&#039;how to implement&#039;&#039;&#039; the backup feature for various Moodle 2.x plugins, mainly, modules and blocks. &lt;br /&gt;
&lt;br /&gt;
Note that, at the time of writing this, the backup &amp;amp; restore subsystem itself is &#039;&#039;&#039;under development&#039;&#039;&#039;, so still there are some missing bits, specially about the way to handle &#039;&#039;&#039;subplugins&#039;&#039;&#039; (question types, data fields...) under the new backup infrastructure, so any module using such artifacts, like data, assignment, quiz, workshop, aren&#039;t  good candidates right now. This will be addressed (and this Docs updated) once we have determined how each subplugin is expected to work (from a DB / backup perspective).&lt;br /&gt;
&lt;br /&gt;
Everything in backup &#039;&#039;&#039;is about tasks and steps&#039;&#039;&#039; (see [[Backup 2.0 general architecture|Backup 2.0 general architecture]] for more information), all them conforming one backup plan. Each module instance and each block instance will be backup by one backup task instance that is, basically, one collection of backup steps. How steps are organized within the task will dictate to the backup system what to do and in which order.&lt;br /&gt;
&lt;br /&gt;
Another important point is that Moodle backup 2.0, supports &#039;&#039;&#039;multiple backup formats&#039;&#039;&#039; (&amp;quot;moodle2&amp;quot;, &amp;quot;imscc&amp;quot;...) each one having its own tasks/steps, completely unrelated between them. In any case, for now, we are focusing all the explanations below in the &amp;quot;moodle2&amp;quot; format, that is the one required in order to keep any module/block &#039;&#039;&#039;transportable between Moodle instances&#039;&#039;&#039; without any loss of data. Surely, for the rest of formats, we&#039;ll end with other documents describing them, since each one can have its own particularities.&lt;br /&gt;
&lt;br /&gt;
Talking about backup steps we must differentiate &#039;&#039;&#039;two type of steps&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Execution steps&#039;&#039;&#039;: That, simply, execute arbitrary PHP code. They are useful to prepare different structures, create directories, whatever have to be done not involving the generation of XML files. Normally you won&#039;t need them.&lt;br /&gt;
* &#039;&#039;&#039;Structure steps&#039;&#039;&#039;: That, using one PHP API (detailed below) define completely the XML structure to be exported and its contents. Hopefully, &amp;quot;normal&amp;quot; modules only will have to use one step of this type in order to have the backup functionality 100% implemented.&lt;br /&gt;
&lt;br /&gt;
Said that, in the next steps we are going through all the steps necessary to create the backup of one simple module and one block, in order to get all the possibilities covered.&lt;br /&gt;
&lt;br /&gt;
== How to backup one module ==&lt;br /&gt;
&lt;br /&gt;
For this section, we have selected one simple module (choice) that requires practically all the backup &amp;quot;machinery&amp;quot; to be used, so it will get explained as we progress in the development. The only point not covered here are the &amp;quot;subplugin&amp;quot; facilities, covered later in a separate section.&lt;br /&gt;
&lt;br /&gt;
=== Prerequisites ===&lt;br /&gt;
&lt;br /&gt;
In order to achieve the backup implementation for the module, some prerequisites should be fulfilled.  They are default recommendations that are especially helpful while getting used to the backup process.&lt;br /&gt;
&lt;br /&gt;
# &#039;&#039;&#039;Learn about the module&#039;&#039;&#039;. If you aren&#039;t the creator of the module, spend some time playing with the module, creating and using it, exploring each one of its functionalities. By doing this you will end with some &amp;quot;real&amp;quot; data in the module instances that will be really useful when testing / debugging how the module backup is being generated.&lt;br /&gt;
# &#039;&#039;&#039;Draw one schema of the module&#039;&#039;&#039; DB structures. While you are playing with the module, look continuously to the DB, how records are saved and what the relationships are between the module&#039;s tables. Since a backup is, basically, one &amp;quot;selective dump&amp;quot; of those tables, knowing the maximum about them is highly recommended. At the end, you must end with one tree structure will be the basis for the generated XML file.&lt;br /&gt;
# &#039;&#039;&#039;Annotate which tables contain user-related info&#039;&#039;&#039; and which ones don&#039;t. One of the core functionalities that must be present on each module is the ability to include user related information or skip it, as you will need that information later.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Tip&#039;&#039;&#039;: If the module already existed before Moodle 2.0, it can be a &#039;&#039;&#039;good idea&#039;&#039;&#039; to look at its 1.9 backuplib.php file, since the structure is already defined there and can help to understand the organization better and, at the same time, &#039;&#039;&#039;keeping the XML structure as similar as possible&#039;&#039;&#039;, that will, definitively, &#039;&#039;&#039;make things easier&#039;&#039;&#039; when converting 1.9 backup files to the new backup 2.0 format.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: It&#039;s important to highlight that the structure schema, should be as stable as possible moving forward, because any change in the structure makes restore much more complex to implement. There aren&#039;t problems with adding/deleting fields, nor adding new elements to the structure. &#039;&#039;&#039;The structure (tree) itself must persist as stable as possible&#039;&#039;&#039;, so be careful when deciding it, as it will have implications on future maintenance.&lt;br /&gt;
&lt;br /&gt;
Applying these pre-requisites to our candidate module (choice), here it&#039;s the corresponding schema. We&#039;ll use it along the whole process.&lt;br /&gt;
&lt;br /&gt;
=== Schema ===&lt;br /&gt;
&lt;br /&gt;
In the schema, you must try to put as much information as possible, so that will produce the coding process later to be quicker and easier while keeping the final results free from errors and missing bits. So, once more, don&#039;t start coding immediately, instead spend some time with the requisites above, understanding how the module works and designing the final structure that represents it better.&lt;br /&gt;
&lt;br /&gt;
==== The (correct) candidate ====&lt;br /&gt;
&lt;br /&gt;
[[Image:Backup20 choice alt.png‎|left|Alternative choice backup structure]]&lt;br /&gt;
&lt;br /&gt;
The tree on the left shows the ER/DB structure of the choice module, where one choice have one or more options and each option is answered by users one or more times (note: ignore cardinality accuracy in the previous phrase).&lt;br /&gt;
&lt;br /&gt;
And that&#039;s the best schema representing the structure of the module, with each element properly nested so, we won&#039;t have any problem with restore since the order required by restore (1, 2, 3) are naturally given. &lt;br /&gt;
&lt;br /&gt;
Looks easy, cool, but continue reading… you will get surprised! :-)&amp;lt;br style=&amp;quot;clear: both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== The (chosen) candidate ====&lt;br /&gt;
&lt;br /&gt;
Instead we are going to use the (complete this time) diagram below. See the rationale about that after the image.&lt;br /&gt;
&lt;br /&gt;
[[Image:Backup20 choice.png‎|center|Used choice backup structure]]&lt;br /&gt;
&lt;br /&gt;
The main reason to use this tree (instead of the &amp;quot;correct&amp;quot; one) is that this is the structure that has been used by Moodle 1.9 backup since ages ago for the choice module and, of course have done its work ok. As commented above we must &#039;&#039;&#039;try to reduce the number of structural changes&#039;&#039;&#039; in one module backup in order to keep the restore operations working along the time (the same is applicable for the conversion of 1.9 backup files to the new 2.0 format). Finally, this is a good example about how one module &#039;&#039;&#039;can have different XML representations&#039;&#039;&#039; and we need to try to get that best one (this is not the case) on each case. So, once more, &#039;&#039;&#039;spending some time analyzing&#039;&#039;&#039; the activity is worth it.&lt;br /&gt;
&lt;br /&gt;
Let&#039;s analyze the schema with some detail:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Detecting user information&#039;&#039;&#039;: We must be able to define the entities (tables) in the diagram that are used to store user information. One of the core features of the backup subsystem since its early days have been the ability to produce backup with and without user information. So we need that info. Hence, the &amp;quot;no user info&amp;quot; in the choice and choice_options elements (they are configuration, user-independent), while the choice_answers is marked as &amp;quot;user info&amp;quot; (contains user&#039;s answers to the choice).&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Determining the correct order of backup&#039;&#039;&#039;: This, while simple, is critical too (especially from a restore perspective). Since the restore reads progressively the xml file and performs actions in that order, we &#039;&#039;&#039;must guarantee that the &amp;quot;read order&amp;quot; is the correct&#039;&#039;&#039; one, fulfilling any possible dependency. Back to our schema it&#039;s clear that we need to backup the &amp;quot;choice&amp;quot; element at first, and then the &amp;quot;choice_options&amp;quot; and &amp;quot;choice_answers&amp;quot; ones. Moreover, the &amp;quot;choice_options&amp;quot; must be backup before &amp;quot;choice_answers&amp;quot;, since the later needs to save the values of the former (the &amp;quot;optionid&amp;quot; information). Note that, as commented some paragraphs above, the &amp;quot;correct&amp;quot; alternative really gave us that order information easily. Doesn&#039;t matter, since we have been able to establish it also in the &amp;quot;chosen&amp;quot; schema.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Attributes and elements&#039;&#039;&#039;: Now it&#039;s time to decide which fields will be considered attributes in the resulting XML file and which ones will be child elements (tags). The rule is simple: &#039;&#039;&#039;All the &amp;quot;id&amp;quot; fields must (should) be defined as attributes&#039;&#039;&#039;. Note this is just one arbitrary rule without much rationale behind it since, from a restore perspective, everything (attributes and child tags) will be handled in the same way (object attributes). So, in our schema, all the &amp;quot;id&amp;quot; fields have been marked as &amp;quot;attr&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Not needed elements&#039;&#039;&#039;: If we have designed the schema properly, we&#039;ll find that some fields aren&#039;t necessary, since such information is already included in some parent element. In our schema, the field &amp;quot;choiceid&amp;quot;, pointing to the &amp;quot;choice-&amp;gt;id&amp;quot;, both in the options and in the answer elements, have been marked as &amp;quot;not needed&amp;quot; since their parent &amp;quot;choice&amp;quot; already contains it. Something similar happens with the &amp;quot;course&amp;quot; field in the choice element. It doesn&#039;t need to be included in the backup file since something above it (course element, outside the module scope) already has it defined. Finally, there is one element marked as &amp;quot;needed&amp;quot; that shows us, once more, that the schema we are using is not the best. Since &amp;quot;choice_answers&amp;quot; isn&#039;t nested under &amp;quot;choice_options&amp;quot;, we must keep the &amp;quot;choice_answers-&amp;gt;optionid&amp;quot; field in the backup, or restore won&#039;t know to which option each answer belongs to. Instead, with the &amp;quot;correct&amp;quot; schema, where answers are nested under options, that field is not needed. Summarizing, &#039;&#039;&#039;any field except those already existing in parent elements must be included in backup&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;Detecting file areas used by the module&#039;&#039;&#039;: Along the module we can be using various file areas in different elements and fields. We need to know exactly which file area is handled by which element and the (optional) itemid information used for that file area. In general, &#039;&#039;&#039;anything being one text field, or anything looking like one attachment&#039;&#039;&#039; has high chances to have one (hidden) file area associated. In our schema, we have one file area (choice_intro) corresponding to the introduction of the module and available to put any images or whatever in that field. Also, in general, all the &amp;quot;xxx_intro&amp;quot; file areas use to have no itemid, since the module&#039;s context is enough to define them without ambiguities. So, we mark the choice-&amp;gt;intro as &amp;quot;choice_intro&amp;quot; file area and &amp;quot;no itemid&amp;quot;). From our expertise playing with the module we know there are no more file areas associated with this module.&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;span id=&amp;quot;annotate_is_important&amp;quot;&amp;gt;&#039;&#039;&#039;Annotating some important bits&#039;&#039;&#039;:&amp;lt;/span&amp;gt; Due to the modularity of the backup and in order to know exactly which information must be saved (because it&#039;s used) and which one can be skipped, &#039;&#039;&#039;it&#039;s important to annotate some important elements along the whole backup&#039;&#039;&#039; process. So, back to our schema, we have marked the &amp;quot;choice_answer-&amp;gt;userid&amp;quot; field as &amp;quot;annotation&amp;quot; (so backup will, automatically, add all the information for that user). Here it&#039;s the list of elements that we must not forget to annotate (or we could end with non-restorable backups). Note that we must, always, be annotating &amp;quot;id&amp;quot; values and not other types of data:&lt;br /&gt;
** &#039;&#039;&#039;user&#039;&#039;&#039;: Any field pointing to one user-&amp;gt;id present along the schema (as said above, our schema has one).&lt;br /&gt;
** &#039;&#039;&#039;grouping&#039;&#039;&#039;: Any field pointing to one grouping-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;group&#039;&#039;&#039;: Any field pointing to one group-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;role&#039;&#039;&#039;: Any field pointing to one role-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;scale&#039;&#039;&#039;: Any field pointing to one scale-&amp;gt;id&lt;br /&gt;
** &#039;&#039;&#039;outcome&#039;&#039;&#039;: Any field pointing to one outcome-&amp;gt;id&lt;br /&gt;
&lt;br /&gt;
And this is all the information we need to know, before starting to code. Surely, once used to backup and restore, you will be able to start coding sooner, but &#039;&#039;&#039;don&#039;t forget about the importance of choosing one good and stable structure&#039;&#039;&#039; before anything else. It&#039;s really the critical part of any module&#039;s backup.&lt;br /&gt;
&lt;br /&gt;
That said, let&#039;s see how to code all this information in order to get one cool backup for our beloved module.&lt;br /&gt;
&lt;br /&gt;
=== Coding ===&lt;br /&gt;
&lt;br /&gt;
Already here? Have you read, at least once, all the explanations and comments in the previous sections? Yes? Sure? I can imagine it&#039;s hard to read so much text, just imagine how hard is to write it! Go, go, go and read it!&lt;br /&gt;
&lt;br /&gt;
Jokes aside, in this section we are going to code the module&#039;s (choice, in our example) backup code. As you&#039;ll see soon, all the information gathered in previous steps is really important and will make the coding task easier and less prone to errors.&lt;br /&gt;
&lt;br /&gt;
==== Setting up the environment ====&lt;br /&gt;
&lt;br /&gt;
By default, any backup operation will end with one .zip file stored in some course / section / activity area. That means that, each time you execute one backup, you&#039;ll need to go across the web interface to that file area, download the generated .zip file, uncompress it, and then see how things have been generated. And you will be executing a bunch of backup files until you get everything working as expected, so the whole develop / test process isn&#039;t really &amp;quot;agile&amp;quot;. To improve things a bit, there is one $CFG setting that you should consider using &#039;&#039;&#039;in your development environment&#039;&#039;&#039;. Just put this in your config.php:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$CFG-&amp;gt;keeptempdirectoriesonbackup = true;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
With this setting enabled, backup won&#039;t delete the temporary directory where everything is calculated, so you will be able to access to it directly, skipping all the ui / download / unzip steps above. Those temp directories are under $CFG-&amp;gt;dataroot/temp/backup. Note that, for each backup invocation, a new directory is created.&lt;br /&gt;
&lt;br /&gt;
Also, in order to be able to execute backups quickly (instead of navigating along the UI), you can, simply, put one script like this in your $CFG-&amp;gt;dirroot directory:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
define(&#039;CLI_SCRIPT&#039;, 1);&lt;br /&gt;
require_once(&#039;config.php&#039;);&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/backup/util/includes/backup_includes.php&#039;);&lt;br /&gt;
&lt;br /&gt;
$course_module_to_backup = XX; // Set this to one existing choice cmid in your dev site&lt;br /&gt;
$user_doing_the_backup   = YY; // Set this to the id of your admin accouun&lt;br /&gt;
&lt;br /&gt;
$bc = new backup_controller(backup::TYPE_1ACTIVITY, $course_module_to_backup, backup::FORMAT_MOODLE,&lt;br /&gt;
                            backup::INTERACTIVE_NO, backup::MODE_GENERAL, $user_doing_the_backup);&lt;br /&gt;
$bc-&amp;gt;execute_plan();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
just set proper values for XX and YY above and execute it from the command line. If you get one error about one not found class (with the name of your module) everything is ok.&lt;br /&gt;
&lt;br /&gt;
==== Required stuff ====&lt;br /&gt;
&lt;br /&gt;
The first thing you need to make is to, explicitly, declare that your module (choice in our example) is going to support the MOODLE2 backup format, to do so, you need to go to mod/choice/lib.php and, in the choice_supports() function add one new feature by adding this line:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
case FEATURE_BACKUP_MOODLE2:          return true;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
If you execute another backup (with the script provided above, you will continue getting one error, since we haven&#039;t still coded anything related to backup, that&#039;s ok.&lt;br /&gt;
&lt;br /&gt;
Next step is to create the directory where all the backup code for the choice module will be. Just create the directory(s) mod/choice/backup/moodle2&lt;br /&gt;
&lt;br /&gt;
At this point, we have all the required stuff ready and all the pending tasks will be done under that recently created directory.&lt;br /&gt;
&lt;br /&gt;
==== Settings, Steps and Tasks ====&lt;br /&gt;
&lt;br /&gt;
In the introduction of the tutorial, we commented about backup being structured into tasks, each one being one collection of steps (and potentially using some custom settings). Those are, exactly, the objects that we need to create to achieve the backup functionality in our module.&lt;br /&gt;
&lt;br /&gt;
First of all, lets&#039; create the settings file, where all the custom settings to be used by our module will be defined and implemented. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_settingslib.php&#039;&#039;&#039; and their contents are really meaningful:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&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;
 * @package moodlecore&lt;br /&gt;
 * @subpackage backup-moodle2&lt;br /&gt;
 * @copyright 2010 onwards YOUR_NAME_GOES_HERE {@link YOUR_URL_GOES_HERE}&lt;br /&gt;
 * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later&lt;br /&gt;
 */&lt;br /&gt;
&lt;br /&gt;
 // This activity has not particular settings but the inherited from the generic&lt;br /&gt;
 // backup_activity_task so here there isn&#039;t any class definition, like the ones&lt;br /&gt;
 // existing in /backup/moodle2/backup_settingslib.php (activities section)&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Looks simple, isn&#039;t it? Nothing but a few comments. This is looking really easy. For now, we aren&#039;t going to introduce any custom setting for any module, only the &amp;quot;core activity settings&amp;quot; will be used. Once backup and Moodle 2.0 is stable we can start analyzing useful settings to customize how the module&#039;s backup is performed. For now, just leave it blank, please. In fact, if it&#039;s empty,&#039;&#039;&#039; you can safely not create it&#039;&#039;&#039; at all. It&#039;s here just for explanation purposes.&lt;br /&gt;
&lt;br /&gt;
Side note: To save some space, we only will be showing the © message/license in the code above. Just add it to each file created.&lt;br /&gt;
&lt;br /&gt;
Now we are going to create the steps file, where all the steps to be executed by our backup activity task will be defined and implemented. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;&#039;&#039; and their contents are these:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * Define all the backup steps that will be used by the backup_choice_activity_task&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Yes, it&#039;s another empty file. No worries we&#039;ll fill it later.&lt;br /&gt;
&lt;br /&gt;
Finally we need to create the task file, where our just created settings and steps files will be included and used. It must be named &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_activity_task.class.php&#039;&#039;&#039; and their contents are these:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
&amp;lt;?php&lt;br /&gt;
&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;); // Because it exists (must)&lt;br /&gt;
require_once($CFG-&amp;gt;dirroot . &#039;/mod/choice/backup/moodle2/backup_choice_settingslib.php&#039;); // Because it exists (optional)&lt;br /&gt;
&lt;br /&gt;
/**&lt;br /&gt;
 * choice backup task that provides all the settings and steps to perform one&lt;br /&gt;
 * complete backup of the activity&lt;br /&gt;
 */&lt;br /&gt;
class backup_choice_activity_task extends backup_activity_task {&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular settings this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_settings() {&lt;br /&gt;
        // No particular settings for this activity&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Define (add) particular steps this activity can have&lt;br /&gt;
     */&lt;br /&gt;
    protected function define_my_steps() {&lt;br /&gt;
        // Choice only has one structure step&lt;br /&gt;
    }&lt;br /&gt;
&lt;br /&gt;
    /**&lt;br /&gt;
     * Code the transformations to perform in the activity in&lt;br /&gt;
     * order to get transportable (encoded) links&lt;br /&gt;
     */&lt;br /&gt;
    static public function encode_content_links($content) {&lt;br /&gt;
        return $content;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This is the main file (class) of the choice backup and it will be used to define any setting (define_my_settings()  method) and any step (define_my_steps() method) to be executed in the backup process. It also contains one 3rd method (encode_content_links($content)) that will allow manually URLs pointing to the choice to be properly converted when the choice is moved to other site / course using the backup / restore functionality.&lt;br /&gt;
&lt;br /&gt;
As you see, for now, the three required methods are doing nothing. Just execute the backup again. Wow, no errors anymore. We have already fulfilled all the minimum coding needs in order to have the choice backup working. &lt;br /&gt;
&lt;br /&gt;
Now you should go to your $CFG-&amp;gt;dataroot/temp/backup/xxxx directory (the more recent) and spend some time looking what has been created under the activities/choice_XX directory. There is already a lot of stuff that backup has generated for you: comments, blocks, logs, grades, module info, roles... some of them empty and others already showing real information.&lt;br /&gt;
&lt;br /&gt;
In any case, now, we need to add one important file there, the &amp;quot;choice.xml&amp;quot; where the real information for your module will be present, following the specs given by the schema we decided some sections above.&lt;br /&gt;
&lt;br /&gt;
So, let&#039;s go, it&#039;s time to create our choice structure step. To do so, we edit the &#039;&#039;&#039;mod/choice/backup/moodle2/backup_choice_stepslib.php&#039;&#039;&#039; file and add this code after the existing comments:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Define the complete choice structure for backup, with file and id annotations&lt;br /&gt;
 */     &lt;br /&gt;
class backup_choice_activity_structure_step extends backup_activity_structure_step {&lt;br /&gt;
&lt;br /&gt;
    protected function define_structure() {&lt;br /&gt;
&lt;br /&gt;
        // To know if we are including userinfo&lt;br /&gt;
        $userinfo = $this-&amp;gt;get_setting_value(&#039;userinfo&#039;);&lt;br /&gt;
&lt;br /&gt;
        // Define each element separated&lt;br /&gt;
&lt;br /&gt;
        // Build the tree&lt;br /&gt;
&lt;br /&gt;
        // Define sources&lt;br /&gt;
&lt;br /&gt;
        // Define id annotations&lt;br /&gt;
&lt;br /&gt;
        // Define file annotations&lt;br /&gt;
&lt;br /&gt;
        // Return the root element (choice), wrapped into standard activity structure&lt;br /&gt;
&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So, we have defined one structure step that will be the responsible, using one PHP API to provide backup with all the information needed to generate the choice.xml file. Now, go back to the task file and add these contents in the define_my_steps() methods:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $this-&amp;gt;add_step(new backup_choice_activity_structure_step(&#039;choice_structure&#039;, &#039;choice.xml&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That way, our choice task knows it must execute one new step, the one involving the generation of the choice.xml file. Let&#039;s execute one new backup and see results.You should be getting one new error with something like that &amp;quot;backup_structure_step_wrong_structure&amp;quot;. It means that everything is ok up to now, the task has tried to execute the structure step, but this is not properly defined.&lt;br /&gt;
&lt;br /&gt;
===== Defining each element =====&lt;br /&gt;
&lt;br /&gt;
So, next step is about to define the choice structure. Going back to our step, under the &#039;&#039;// Define each element separate&#039;&#039; comment we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $choice = new backup_nested_element(&#039;choice&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;name&#039;, &#039;intro&#039;, &#039;introformat&#039;, &#039;publish&#039;,&lt;br /&gt;
            &#039;showresults&#039;, &#039;display&#039;, &#039;allowupdate&#039;, &#039;allowunanswered&#039;,&lt;br /&gt;
            &#039;limitanswers&#039;, &#039;timeopen&#039;, &#039;timeclose&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&lt;br /&gt;
        $options = new backup_nested_element(&#039;options&#039;);&lt;br /&gt;
&lt;br /&gt;
        $option = new backup_nested_element(&#039;option&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;text&#039;, &#039;maxanswers&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&lt;br /&gt;
        $answers = new backup_nested_element(&#039;answers&#039;);&lt;br /&gt;
&lt;br /&gt;
        $answer = new backup_nested_element(&#039;answer&#039;, array(&#039;id&#039;), array(&lt;br /&gt;
            &#039;userid&#039;, &#039;optionid&#039;, &#039;timemodified&#039;));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===== Return the root element =====&lt;br /&gt;
&lt;br /&gt;
And also, in order to get it working, let&#039;s define the return element, so, after the &#039;&#039;// Return the root element&#039;&#039; comment, add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        return $this-&amp;gt;prepare_activity_structure($choice);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now we can execute the backup again and, as long as we have already defined the root element of the module, should have now one choice.xml file created (without proper contents but must be there).&lt;br /&gt;
&lt;br /&gt;
About the code above, all we have done is to define, separately each element that will be part of the choice.xml file. Special note about the $options and $answers elements. Since Moodle 1.9 we use to enclose real elements (the singular ones) inside one extra plural element, hence we create them here (as empty elements without attributes nor child tags). About the rest (the singular ones) we use 3 params in the instantiation:&lt;br /&gt;
* The name of the element&lt;br /&gt;
* One array of attributes of the element&lt;br /&gt;
* One array of child tags (fields) of the element.&lt;br /&gt;
And we include all the fields that previously we had defined in our schema &#039;&#039;&#039;but&#039;&#039;&#039; the ones marked as &#039;&#039;&#039;not needed&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
===== Building the tree =====&lt;br /&gt;
&lt;br /&gt;
Now it&#039;s time to declare the relations between all those elements, so, after the &#039;&#039;// Build the tree&#039;&#039; comment we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;add_child($options);&lt;br /&gt;
        $options-&amp;gt;add_child($option);&lt;br /&gt;
&lt;br /&gt;
        $choice-&amp;gt;add_child($answers);&lt;br /&gt;
        $answers-&amp;gt;add_child($answer);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Self explanatory, using $choice as root element, we define the whole tree using the add_child() method. And, of course, we respect &#039;&#039;&#039;the order&#039;&#039;&#039; that we had decided, so $options will be &#039;&#039;&#039;physically&#039;&#039;&#039; before $answers in the tree (and in the generated XML).&lt;br /&gt;
&lt;br /&gt;
===== Defining the sources =====&lt;br /&gt;
&lt;br /&gt;
After this, it&#039;s the moment to instruct our tree about how to fetch information from DB in order to generate the choice.xml file, so after the &#039;&#039;// Define sources&#039;&#039; comment, we&#039;ll add this code:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;set_source_table(&#039;choice&#039;, array(&#039;id&#039; =&amp;gt; backup::VAR_ACTIVITYID));&lt;br /&gt;
&lt;br /&gt;
        $option-&amp;gt;set_source_sql(&#039;&lt;br /&gt;
            SELECT *&lt;br /&gt;
              FROM {choice_options}&lt;br /&gt;
             WHERE choiceid = ?&#039;,&lt;br /&gt;
            array(backup::VAR_PARENTID));&lt;br /&gt;
&lt;br /&gt;
        // All the rest of elements only happen if we are including user info&lt;br /&gt;
        if ($userinfo) {&lt;br /&gt;
            $answer-&amp;gt;set_source_table(&#039;choice_answers&#039;, array(&#039;choiceid&#039; =&amp;gt; &#039;../../id&#039;));&lt;br /&gt;
        }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
So we define the source for the $choice element as the information present in the &#039;choice&#039; table for the id that is being backup (backup::VAR_ACTIVITYID). Or we define the source for the $option element like one SQL (could have been one table too, just to show more possibilities of the API, using the parent (the choice one) as value for the query (backup::VAR_PARENTID).&lt;br /&gt;
&lt;br /&gt;
And finally, conditionally, if user information is going to be included, we define the source for the $answer (note we had already annotated in our schema that this element was dependent of that). &lt;br /&gt;
&lt;br /&gt;
And we define the source condition as having the &#039;choiceid&#039; field matching the value of the &#039;id&#039; field two levels above (../../id). If you follow the tree created in the previous code section, that&#039;s exactly the choice-&amp;gt;id (remember we have introduced one extra level (the plural one between the &#039;choice&#039; and the &#039;answer&#039; singular elements). Note this is 100% equivalent to use backup::VAR_PARENTID (as we have done in the $option source) just used to show possibilities of the API.&lt;br /&gt;
&lt;br /&gt;
Summarizing, with the API, we have these 3 method for defining sources:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;set_source_table($tablename, array $conditions)&#039;&#039;&#039;: When the information is get straight from one table (vast majority of cases in backup)&lt;br /&gt;
* &#039;&#039;&#039;set_source_sql($sql, array $params)&#039;&#039;&#039;: When the information doesn&#039;t map one table directly and we need something more complex&lt;br /&gt;
* &#039;&#039;&#039;set_source_array($array)&#039;&#039;&#039;: When we have some fixed information to backup. Not really useful in nested information, but used by core here and there.&lt;br /&gt;
&lt;br /&gt;
Note that both the $conditions and $params above only accept one limited number of constants or values (not all available in all backups!), mainly:&lt;br /&gt;
&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_COURSEID&#039;&#039;&#039;: The id of the course this activity belongs to / the course id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_SECTIONID&#039;&#039;&#039;: The id of the section this activity belongs to / the section id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_ACTIVITYID&#039;&#039;&#039;: The id of the activity id being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_MODID&#039;&#039;&#039;: The id of the course_module being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_MODULENAME&#039;&#039;&#039;: The name of the module being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_BLOCKID&#039;&#039;&#039;: The id of the block being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_BLOCKNAME&#039;&#039;&#039;: The name of the block being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_CONTEXTID&#039;&#039;&#039;: The context id of the activity / course being backup&lt;br /&gt;
* &#039;&#039;&#039;backup::VAR_PARENTID&#039;&#039;&#039;: The value of the first parent id found in the structure.&lt;br /&gt;
* &#039;&#039;&#039;../some/path/to/parent&#039;&#039;&#039;: To manually point to other value of any parent.&lt;br /&gt;
&lt;br /&gt;
Is important to note that, in 99% of the case we should be using, exclusively, some of the constants above, and backup, automatically will handle them properly. In case we have any other condition or param to be added like, for example, the number 23, or the string &#039;user&#039;, we cannot add them directly, but enclose them with the helper &#039;&#039;&#039;backup_helper::is_sqlparam(23)&#039;&#039;&#039; or &#039;&#039;&#039;backup_helper::is_sqlparam(&#039;user&#039;)&#039;&#039;&#039;. That way backup will know they are raw SQL params not needing any special handling, like the constants above.&lt;br /&gt;
&lt;br /&gt;
Well, now it&#039;s time to run backup again and take a look to our activities/choice_XX/choice.xml file. Now everything should be there, properly nested, the choice, the options and the answers. We are really near finishing now.&lt;br /&gt;
&lt;br /&gt;
===== Annotating IDs =====&lt;br /&gt;
&lt;br /&gt;
Now it&#039;s time to perform all the annotations that we had already detected in our analysis of the module. So, after the &#039;&#039;// Define id annotations&#039;&#039; comment we&#039;ll be adding:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $answer-&amp;gt;annotate_ids(&#039;user&#039;, &#039;userid&#039;);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
It simply means, annotate for each $answer element, the value of the &#039;userid&#039; field as one &#039;user&#039; to be backup. In other words we are instructing backup that there is one new user to include later, when generating the users information and, at the same time, we are determining that those users are needed for the choice XX, so, if on restore we decide to skip that choice and such user isn&#039;t necessary for any other module / subsystem, it won&#039;t be restored. All this &amp;quot;uses&amp;quot; information is handled by the &amp;quot;inforef.xml&amp;quot; files within each activity backup, just in case you&#039;re interested to take a look to them. Else, just consider them, &amp;quot;dark magic&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Note&#039;&#039;&#039;: If you&#039;re not sure about which elements must be annotated, review [[Backup 2.0 for developers #annotate_is_important|&amp;quot;Annotating some important bits&amp;quot;]] above for details about &#039;&#039;&#039;must-be-done&#039;&#039;&#039; annotations.&lt;br /&gt;
&lt;br /&gt;
===== Annotating files =====&lt;br /&gt;
&lt;br /&gt;
And, finally, reviewing our elaborate and detailed schema, the last thing we need to take care of are the file areas used, so, after the &#039;&#039;// Define file annotations&#039;&#039; comment we&#039;ll add:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
        $choice-&amp;gt;annotate_files(&#039;mod_choice&#039;, &#039;intro&#039;, null, $contextid = null); // This file area does not have an itemid.&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
That means that, within the $choice element we have one file area in use, of course belonging to the &#039;mod_choice&#039; component (where all the choice module files belong to), named &#039;intro&#039; and not using itemid (null). Note that, since it is possible to have multiple file areas in the same element (table), you may end up having multiple calls to the annotate_files() method, one for each filearea to be added to backup. The third parameter, if it is needed, must be the name of one of the attributes or fields of the $choice element (usually, in the vast majority of cases, the &#039;id&#039; of the element), otherwise we&#039;ll use null. The fourth parameter is optional and will default to the context id of the backup, but if you want to specify the context id you do so here.&lt;br /&gt;
&lt;br /&gt;
=== One encoded wor(l)d ===&lt;br /&gt;
&lt;br /&gt;
Already out from the step definition, that should be working ok now, with the choice.xml file being generated and all the annotations being processed and added to the inforef.xml file, there is one more point to fulfill before considering choice&#039;s backup 100% finished.&lt;br /&gt;
&lt;br /&gt;
And it&#039;s about how to provide the ability to transform some links to the choice module when the backup file is restored into another server / course. That is automatically handled by a two-step approach:&lt;br /&gt;
# On backup, we transform as many well-know URLs as possible to one encoded form.&lt;br /&gt;
# On restore, we transform those encoded URLS back to their original form, but pointing to their new targets.&lt;br /&gt;
&lt;br /&gt;
So, in backup, we must provide services for the point 1 above, and that is done by adding some &amp;quot;encoding&amp;quot; conversions to the &#039;&#039;&#039;encode_content_links()&#039;&#039;&#039; method in our &#039;&#039;&#039;backup_choice_activity_task&#039;&#039;&#039;. So, define it to look like this&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
    /**&lt;br /&gt;
     * Code the transformations to perform in the activity in&lt;br /&gt;
     * order to get transportable (encoded) links&lt;br /&gt;
     */&lt;br /&gt;
    static public function encode_content_links($content) {&lt;br /&gt;
        global $CFG;&lt;br /&gt;
&lt;br /&gt;
        $base = preg_quote($CFG-&amp;gt;wwwroot,&amp;quot;/&amp;quot;);&lt;br /&gt;
&lt;br /&gt;
        // Link to the list of choices&lt;br /&gt;
        $search=&amp;quot;/(&amp;quot;.$base.&amp;quot;\/mod\/choice\/index.php\?id\=)([0-9]+)/&amp;quot;;&lt;br /&gt;
        $content= preg_replace($search, &#039;$@CHOICEINDEX*$2@$&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
        // Link to choice view by moduleid&lt;br /&gt;
        $search=&amp;quot;/(&amp;quot;.$base.&amp;quot;\/mod\/choice\/view.php\?id\=)([0-9]+)/&amp;quot;;&lt;br /&gt;
        $content= preg_replace($search, &#039;$@CHOICEVIEWBYID*$2@$&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
        return $content;&lt;br /&gt;
    }&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Básically, it gets any URL (manually written) in any content of the backup being generated and transform some (well-known) URLs to one encoded alternative. In this case we are encoding:&lt;br /&gt;
* Any URL pointing to the list of choices in a course == is changed to ==&amp;gt; $@CHOICEINDEX*XX@$&lt;br /&gt;
* Any URL pointing to one exact choice == is changed to ==&amp;gt; $@CHOICEVIEWBYID*YY@$&lt;br /&gt;
&lt;br /&gt;
In restore, well have the opposite conversions happening, replacing the XX and YY above to their new equivalents, so those links will be transportable via backup/restore without any need to edit them manually later.&lt;br /&gt;
&lt;br /&gt;
Tip: Don&#039;t forget to look to the module&#039;s 1.9 backup code, as far as there you&#039;ll find which conversions must be considered to be added here.&lt;br /&gt;
&lt;br /&gt;
=== Final notes ===&lt;br /&gt;
&lt;br /&gt;
* Don&#039;t get stressed, it&#039;s really more difficult / longer to explain than to do it. 100% guaranteed, else we&#039;ll return your money. :-P&lt;br /&gt;
* If you&#039;ve become lost, or your code is not working properly, you always can [https://github.com/moodle/moodle/tree/master/mod/choice/backup/moodle2 see the complete choice working code in git]. Or, alternatively, look to other well known modules, like [https://github.com/moodle/moodle/blob/master/mod/forum/backup/moodle2/ forum] or also the [https://github.com/moodle/moodle/blob/master/backup/moodle2/backup_stepslib.php big core library of steps], where you will find all sort of uses of the API.&lt;br /&gt;
* If you are going to implement backup for module XXXX, just copy this document, replace any &amp;quot;choice&amp;quot; occurrence within it by XXXX and follow it from the beginning to the end. Should work.&lt;br /&gt;
* If the module already existed in Moodle 1.x, try to follow the same structure if possible, that will make things easier for restore / conversion.&lt;br /&gt;
* Right now there are some pending tasks related with different exceptions that will be thrown if you code something wrongly (bad nesting, incorrect field names, bad constant/sql param uses...) and how they are shown. Fix for that will be coming soon.&lt;br /&gt;
* Also, as stated at the beginning of this tutorial, we are still missing &amp;quot;subplugins&amp;quot; final support in modules, so try to avoid implementing backup on them for now. Once ready, there will be one new section in this document about them.&lt;br /&gt;
* Any question / improvement / comment, feel free to contact with Moodle HQ, better if using the Tracker or, alternatively, forums / email / direct contact with your very-best-developer-friend. Note this is version x.0 (dot zero) of the backup API, so sure there are possibilities to improve it along the time.&lt;br /&gt;
&lt;br /&gt;
== Other components that can be backed up ==&lt;br /&gt;
&lt;br /&gt;
Most plugins which can be added to a course can also include data in a course backup. Some examples:&lt;br /&gt;
&lt;br /&gt;
* Course formats&lt;br /&gt;
* Themes: [[ Backup 2.0 theme data| Backup 2.0 theme data]]&lt;br /&gt;
* Plagiarism plugins&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49403</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49403"/>
		<updated>2016-02-03T10:43:16Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Ability to crop/resize/rotate an image in atto */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
&lt;br /&gt;
When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you complete the [http://dev.moodle.org/course/view.php?id=2 Introduction to Moodle Programming] course on [http://dev.moodle.org/ dev.moodle.org]. To access this you will need to have an account on moodle.org first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer]&#039;&#039;. See the [https://moodle.org/mod/forum/discuss.php?d=260354 Plugins adoption programme].&lt;br /&gt;
&lt;br /&gt;
As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ability to crop/resize/rotate an image in atto ===&lt;br /&gt;
&lt;br /&gt;
Moodle comes with it&#039;s own HTML editor known as &#039;atto&#039; (see https://docs.moodle.org/dev/Atto). The editor functions similarly to other editors out there, like TinyMCE, but is tailored to Moodle. It comes with multiple plugins that allow users to perform tasks, such as changing the font size, the alignment, adding links etc. One of these plugins allows the user to add an image to the text editor with the ability to specify the size and alignment of the image via text input. The idea of this project is to extend and improve this current plugin so the user can crop/resize/rotate the image via JS - making the whole experience easier and more aesthetically pleasing.&lt;br /&gt;
&lt;br /&gt;
This project details/discussion can be located at MDL-52982.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: Javascript (YUI), PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/view.php?id=1057750 Mark Nelson]&lt;br /&gt;
&lt;br /&gt;
=== Improve Behat tests in SCORM plugin ===&lt;br /&gt;
The Moodle SCORM plugin does not contain very many behat tests and most tests are manual. The Claude Ostyn diagnostic SCO should be used to implement a range of new Behat tests to cover the functionality that the SCORM module provides.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Behat tests for all existing SCORM QA tests (where possible)&lt;br /&gt;
* Behat tests for all SCORM settings (eg standards mode, mastery score settings etc) &lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Advanced Grading in Forums ===&lt;br /&gt;
Finish the work required to add the advanced grading feature to the Moodle forum activity. This builds on some existing work available at MDL-31860&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Modify the forum grading so that it pushes 2 grade areas (or 3 including ratings) into the gradebook instead of a single grade.&lt;br /&gt;
* Improve interface that allows overall forum participation grading.&lt;br /&gt;
* Behat tests for all new functionality.&lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Add support to end-to-end testing in the Mobile app ===&lt;br /&gt;
&lt;br /&gt;
[https://angular.github.io/protractor/#/ Protractor] is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.&lt;br /&gt;
&lt;br /&gt;
The basements for this project are done, see MOBILE-1179, the only remaining work is to add more tests to the app and document the set-up process in the Moodle developers wiki.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (AngularJS)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Create a desktop version of Moodle Mobile using Electron ===&lt;br /&gt;
&lt;br /&gt;
[http://electron.atom.io/ Electron] is a tool for creating cross platform desktop applications using web technologies.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/moodlehq/moodlemobile/ Moodle Mobile 1] (the previous version of Moodle Mobile) had an experimental desktop application using a similar tool ([http://nwjs.io/ Node-Webkit, now NW.js]), for Moodle Mobile 2 we’d like to see the application packaged for desktop using Electron.&lt;br /&gt;
&lt;br /&gt;
In this project you will implement some of the Cordova APIs to use the Node.js API provided by electron:&lt;br /&gt;
* FileSystem API - For browsing the local file system&lt;br /&gt;
* FileTransfer API - For downloads and uploads&lt;br /&gt;
* Camera and capture API - For taking photos, videos and audios using the webcam&lt;br /&gt;
&lt;br /&gt;
Notice that these APIs are already implemented in the previous version of Moodle Mobile 1, this project is about migrating this old APIs from Node-Webkit to the new version of the application using Electron.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (Node.js)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Generator of Moodle plugins scaffold code ===&lt;br /&gt;
&lt;br /&gt;
There are many [[Plugin types|plugin types]] in Moodle. There are [[Plugin files|files]] and code patterns that all plugins have in common. Also there are specific interfaces that individual plugin types are expected to implement. When developing a new plugin, Moodle contributors use some available templates for various plugin types as well as existing plugins as a reference.&lt;br /&gt;
&lt;br /&gt;
The goal of this project is to develop a tool that helps Moodle contributors to generate a scaffold code for a new Moodle plugin. Given parameters such as plugin type, plugin name, list of enabled/disabled features and other meta-data (such as author name etc), the tool should generate a scaffold code for that plugin that the developer can build on.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Research and analysis of existing tools and approaches used in other software projects.&lt;br /&gt;
* Specification of the format/syntax of templates that will be used to generate the plugin code (consider Mustache as it is templating language that Moodle developers are most familiar with).&lt;br /&gt;
* Templates for all Moodle plugin types and specification of their storage, organisation and maintenance (so that it is possible to keep them up to date in further Moodle versions).&lt;br /&gt;
* Software tool that makes use of these templates and actually generates the plugin scaffold code.&lt;br /&gt;
&lt;br /&gt;
Requirements:&lt;br /&gt;
* The generated code should pass 100% of the Moodle codechecking tools to ensure it meets with Moodle Guidelines.&lt;br /&gt;
* The generator itself should be written in either PHP or JavaScript (Node.js) and provide both CLI and GUI.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP / Node.js, experience with Moodle plugins development is a big plus.&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add search to more moodle components ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. There are some module components, like glossary or databases that can use the search engine to index their data on it, so moodle users with permissions can access them quickly. This project would be about implementing the search API in some moodle components, the number of components can vary depending on the time available, but ideally this should land into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
=== Elastic search ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. The only search engine that will be initially supported will be solr, as elasticsearch has a good use base would be nice to write a search_elastic plugin implementing moodle&#039;s search engine API. This does not necessarily need to go into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;br /&gt;
* [[Projects for new developers/Archive|Archive]] of outdated and/or inactive calls for projects&lt;br /&gt;
* [https://docs.moodle.org/dev/Moodle_Wishlist a Wishlist] by some Moodle users. Some of the good ideas here may be adopted.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49402</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49402"/>
		<updated>2016-02-03T10:41:28Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Ability to crop/resize/rotate an image in atto */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
&lt;br /&gt;
When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you complete the [http://dev.moodle.org/course/view.php?id=2 Introduction to Moodle Programming] course on [http://dev.moodle.org/ dev.moodle.org]. To access this you will need to have an account on moodle.org first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer]&#039;&#039;. See the [https://moodle.org/mod/forum/discuss.php?d=260354 Plugins adoption programme].&lt;br /&gt;
&lt;br /&gt;
As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ability to crop/resize/rotate an image in atto ===&lt;br /&gt;
&lt;br /&gt;
Moodle comes with it&#039;s own HTML editor known as &#039;atto&#039;. The editor functions similarly to other editors out there, like TinyMCE, but is tailored to Moodle. It comes with multiple plugins that allow users to perform tasks, such as changing the font size, the alignment, adding links etc. One of these plugins allows the user to add an image to the text editor with the ability to specify the size and alignment of the image via text input. The idea of this project is to extend and improve this current plugin so the user can crop/resize/rotate the image via JS - making the whole experience easier and more aesthetically pleasing.&lt;br /&gt;
&lt;br /&gt;
This project details/discussion can be located at MDL-52982.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: Javascript (YUI), PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/view.php?id=1057750 Mark Nelson]&lt;br /&gt;
&lt;br /&gt;
=== Improve Behat tests in SCORM plugin ===&lt;br /&gt;
The Moodle SCORM plugin does not contain very many behat tests and most tests are manual. The Claude Ostyn diagnostic SCO should be used to implement a range of new Behat tests to cover the functionality that the SCORM module provides.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Behat tests for all existing SCORM QA tests (where possible)&lt;br /&gt;
* Behat tests for all SCORM settings (eg standards mode, mastery score settings etc) &lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Advanced Grading in Forums ===&lt;br /&gt;
Finish the work required to add the advanced grading feature to the Moodle forum activity. This builds on some existing work available at MDL-31860&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Modify the forum grading so that it pushes 2 grade areas (or 3 including ratings) into the gradebook instead of a single grade.&lt;br /&gt;
* Improve interface that allows overall forum participation grading.&lt;br /&gt;
* Behat tests for all new functionality.&lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Add support to end-to-end testing in the Mobile app ===&lt;br /&gt;
&lt;br /&gt;
[https://angular.github.io/protractor/#/ Protractor] is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.&lt;br /&gt;
&lt;br /&gt;
The basements for this project are done, see MOBILE-1179, the only remaining work is to add more tests to the app and document the set-up process in the Moodle developers wiki.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (AngularJS)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Create a desktop version of Moodle Mobile using Electron ===&lt;br /&gt;
&lt;br /&gt;
[http://electron.atom.io/ Electron] is a tool for creating cross platform desktop applications using web technologies.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/moodlehq/moodlemobile/ Moodle Mobile 1] (the previous version of Moodle Mobile) had an experimental desktop application using a similar tool ([http://nwjs.io/ Node-Webkit, now NW.js]), for Moodle Mobile 2 we’d like to see the application packaged for desktop using Electron.&lt;br /&gt;
&lt;br /&gt;
In this project you will implement some of the Cordova APIs to use the Node.js API provided by electron:&lt;br /&gt;
* FileSystem API - For browsing the local file system&lt;br /&gt;
* FileTransfer API - For downloads and uploads&lt;br /&gt;
* Camera and capture API - For taking photos, videos and audios using the webcam&lt;br /&gt;
&lt;br /&gt;
Notice that these APIs are already implemented in the previous version of Moodle Mobile 1, this project is about migrating this old APIs from Node-Webkit to the new version of the application using Electron.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (Node.js)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Generator of Moodle plugins scaffold code ===&lt;br /&gt;
&lt;br /&gt;
There are many [[Plugin types|plugin types]] in Moodle. There are [[Plugin files|files]] and code patterns that all plugins have in common. Also there are specific interfaces that individual plugin types are expected to implement. When developing a new plugin, Moodle contributors use some available templates for various plugin types as well as existing plugins as a reference.&lt;br /&gt;
&lt;br /&gt;
The goal of this project is to develop a tool that helps Moodle contributors to generate a scaffold code for a new Moodle plugin. Given parameters such as plugin type, plugin name, list of enabled/disabled features and other meta-data (such as author name etc), the tool should generate a scaffold code for that plugin that the developer can build on.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Research and analysis of existing tools and approaches used in other software projects.&lt;br /&gt;
* Specification of the format/syntax of templates that will be used to generate the plugin code (consider Mustache as it is templating language that Moodle developers are most familiar with).&lt;br /&gt;
* Templates for all Moodle plugin types and specification of their storage, organisation and maintenance (so that it is possible to keep them up to date in further Moodle versions).&lt;br /&gt;
* Software tool that makes use of these templates and actually generates the plugin scaffold code.&lt;br /&gt;
&lt;br /&gt;
Requirements:&lt;br /&gt;
* The generated code should pass 100% of the Moodle codechecking tools to ensure it meets with Moodle Guidelines.&lt;br /&gt;
* The generator itself should be written in either PHP or JavaScript (Node.js) and provide both CLI and GUI.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP / Node.js, experience with Moodle plugins development is a big plus.&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add search to more moodle components ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. There are some module components, like glossary or databases that can use the search engine to index their data on it, so moodle users with permissions can access them quickly. This project would be about implementing the search API in some moodle components, the number of components can vary depending on the time available, but ideally this should land into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
=== Elastic search ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. The only search engine that will be initially supported will be solr, as elasticsearch has a good use base would be nice to write a search_elastic plugin implementing moodle&#039;s search engine API. This does not necessarily need to go into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;br /&gt;
* [[Projects for new developers/Archive|Archive]] of outdated and/or inactive calls for projects&lt;br /&gt;
* [https://docs.moodle.org/dev/Moodle_Wishlist a Wishlist] by some Moodle users. Some of the good ideas here may be adopted.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49401</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49401"/>
		<updated>2016-02-03T10:39:28Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Ability to crop/resize/rotate an image in atto */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
&lt;br /&gt;
When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you complete the [http://dev.moodle.org/course/view.php?id=2 Introduction to Moodle Programming] course on [http://dev.moodle.org/ dev.moodle.org]. To access this you will need to have an account on moodle.org first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer]&#039;&#039;. See the [https://moodle.org/mod/forum/discuss.php?d=260354 Plugins adoption programme].&lt;br /&gt;
&lt;br /&gt;
As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ability to crop/resize/rotate an image in atto ===&lt;br /&gt;
&lt;br /&gt;
Moodle comes with it&#039;s own default editor known as &#039;atto&#039;. The editor functions similarly to other editors out there, like TinyMCE, but is tailored to Moodle. It comes with multiple plugins that allow users to perform tasks, such as changing the font size, the alignment, adding links etc. One of these plugins allows the user to add an image to the text editor with the ability to specify the size and alignment of the image via text input. The idea of this project is to extend and improve this current plugin so the user can crop/resize/rotate the image via JS - making the whole experience easier and more aesthetically pleasing.&lt;br /&gt;
&lt;br /&gt;
This project details/discussion can be located at MDL-52982.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: Javascript (YUI), PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/view.php?id=1057750 Mark Nelson]&lt;br /&gt;
&lt;br /&gt;
=== Improve Behat tests in SCORM plugin ===&lt;br /&gt;
The Moodle SCORM plugin does not contain very many behat tests and most tests are manual. The Claude Ostyn diagnostic SCO should be used to implement a range of new Behat tests to cover the functionality that the SCORM module provides.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Behat tests for all existing SCORM QA tests (where possible)&lt;br /&gt;
* Behat tests for all SCORM settings (eg standards mode, mastery score settings etc) &lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Advanced Grading in Forums ===&lt;br /&gt;
Finish the work required to add the advanced grading feature to the Moodle forum activity. This builds on some existing work available at MDL-31860&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Modify the forum grading so that it pushes 2 grade areas (or 3 including ratings) into the gradebook instead of a single grade.&lt;br /&gt;
* Improve interface that allows overall forum participation grading.&lt;br /&gt;
* Behat tests for all new functionality.&lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Add support to end-to-end testing in the Mobile app ===&lt;br /&gt;
&lt;br /&gt;
[https://angular.github.io/protractor/#/ Protractor] is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.&lt;br /&gt;
&lt;br /&gt;
The basements for this project are done, see MOBILE-1179, the only remaining work is to add more tests to the app and document the set-up process in the Moodle developers wiki.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (AngularJS)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Create a desktop version of Moodle Mobile using Electron ===&lt;br /&gt;
&lt;br /&gt;
[http://electron.atom.io/ Electron] is a tool for creating cross platform desktop applications using web technologies.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/moodlehq/moodlemobile/ Moodle Mobile 1] (the previous version of Moodle Mobile) had an experimental desktop application using a similar tool ([http://nwjs.io/ Node-Webkit, now NW.js]), for Moodle Mobile 2 we’d like to see the application packaged for desktop using Electron.&lt;br /&gt;
&lt;br /&gt;
In this project you will implement some of the Cordova APIs to use the Node.js API provided by electron:&lt;br /&gt;
* FileSystem API - For browsing the local file system&lt;br /&gt;
* FileTransfer API - For downloads and uploads&lt;br /&gt;
* Camera and capture API - For taking photos, videos and audios using the webcam&lt;br /&gt;
&lt;br /&gt;
Notice that these APIs are already implemented in the previous version of Moodle Mobile 1, this project is about migrating this old APIs from Node-Webkit to the new version of the application using Electron.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (Node.js)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Generator of Moodle plugins scaffold code ===&lt;br /&gt;
&lt;br /&gt;
There are many [[Plugin types|plugin types]] in Moodle. There are [[Plugin files|files]] and code patterns that all plugins have in common. Also there are specific interfaces that individual plugin types are expected to implement. When developing a new plugin, Moodle contributors use some available templates for various plugin types as well as existing plugins as a reference.&lt;br /&gt;
&lt;br /&gt;
The goal of this project is to develop a tool that helps Moodle contributors to generate a scaffold code for a new Moodle plugin. Given parameters such as plugin type, plugin name, list of enabled/disabled features and other meta-data (such as author name etc), the tool should generate a scaffold code for that plugin that the developer can build on.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Research and analysis of existing tools and approaches used in other software projects.&lt;br /&gt;
* Specification of the format/syntax of templates that will be used to generate the plugin code (consider Mustache as it is templating language that Moodle developers are most familiar with).&lt;br /&gt;
* Templates for all Moodle plugin types and specification of their storage, organisation and maintenance (so that it is possible to keep them up to date in further Moodle versions).&lt;br /&gt;
* Software tool that makes use of these templates and actually generates the plugin scaffold code.&lt;br /&gt;
&lt;br /&gt;
Requirements:&lt;br /&gt;
* The generated code should pass 100% of the Moodle codechecking tools to ensure it meets with Moodle Guidelines.&lt;br /&gt;
* The generator itself should be written in either PHP or JavaScript (Node.js) and provide both CLI and GUI.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP / Node.js, experience with Moodle plugins development is a big plus.&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add search to more moodle components ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. There are some module components, like glossary or databases that can use the search engine to index their data on it, so moodle users with permissions can access them quickly. This project would be about implementing the search API in some moodle components, the number of components can vary depending on the time available, but ideally this should land into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
=== Elastic search ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. The only search engine that will be initially supported will be solr, as elasticsearch has a good use base would be nice to write a search_elastic plugin implementing moodle&#039;s search engine API. This does not necessarily need to go into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;br /&gt;
* [[Projects for new developers/Archive|Archive]] of outdated and/or inactive calls for projects&lt;br /&gt;
* [https://docs.moodle.org/dev/Moodle_Wishlist a Wishlist] by some Moodle users. Some of the good ideas here may be adopted.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49400</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49400"/>
		<updated>2016-02-03T10:29:37Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Allow to crop/resize/rotate images when inserting them */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
&lt;br /&gt;
When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you complete the [http://dev.moodle.org/course/view.php?id=2 Introduction to Moodle Programming] course on [http://dev.moodle.org/ dev.moodle.org]. To access this you will need to have an account on moodle.org first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer]&#039;&#039;. See the [https://moodle.org/mod/forum/discuss.php?d=260354 Plugins adoption programme].&lt;br /&gt;
&lt;br /&gt;
As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Ability to crop/resize/rotate an image in atto ===&lt;br /&gt;
&lt;br /&gt;
This project details are located at MDL-52982.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: Javascript (YUI), PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/view.php?id=1057750 Mark Nelson]&lt;br /&gt;
&lt;br /&gt;
=== Improve Behat tests in SCORM plugin ===&lt;br /&gt;
The Moodle SCORM plugin does not contain very many behat tests and most tests are manual. The Claude Ostyn diagnostic SCO should be used to implement a range of new Behat tests to cover the functionality that the SCORM module provides.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Behat tests for all existing SCORM QA tests (where possible)&lt;br /&gt;
* Behat tests for all SCORM settings (eg standards mode, mastery score settings etc) &lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Advanced Grading in Forums ===&lt;br /&gt;
Finish the work required to add the advanced grading feature to the Moodle forum activity. This builds on some existing work available at MDL-31860&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Modify the forum grading so that it pushes 2 grade areas (or 3 including ratings) into the gradebook instead of a single grade.&lt;br /&gt;
* Improve interface that allows overall forum participation grading.&lt;br /&gt;
* Behat tests for all new functionality.&lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Add support to end-to-end testing in the Mobile app ===&lt;br /&gt;
&lt;br /&gt;
[https://angular.github.io/protractor/#/ Protractor] is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.&lt;br /&gt;
&lt;br /&gt;
The basements for this project are done, see MOBILE-1179, the only remaining work is to add more tests to the app and document the set-up process in the Moodle developers wiki.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (AngularJS)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Create a desktop version of Moodle Mobile using Electron ===&lt;br /&gt;
&lt;br /&gt;
[http://electron.atom.io/ Electron] is a tool for creating cross platform desktop applications using web technologies.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/moodlehq/moodlemobile/ Moodle Mobile 1] (the previous version of Moodle Mobile) had an experimental desktop application using a similar tool ([http://nwjs.io/ Node-Webkit, now NW.js]), for Moodle Mobile 2 we’d like to see the application packaged for desktop using Electron.&lt;br /&gt;
&lt;br /&gt;
In this project you will implement some of the Cordova APIs to use the Node.js API provided by electron:&lt;br /&gt;
* FileSystem API - For browsing the local file system&lt;br /&gt;
* FileTransfer API - For downloads and uploads&lt;br /&gt;
* Camera and capture API - For taking photos, videos and audios using the webcam&lt;br /&gt;
&lt;br /&gt;
Notice that these APIs are already implemented in the previous version of Moodle Mobile 1, this project is about migrating this old APIs from Node-Webkit to the new version of the application using Electron.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (Node.js)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Generator of Moodle plugins scaffold code ===&lt;br /&gt;
&lt;br /&gt;
There are many [[Plugin types|plugin types]] in Moodle. There are [[Plugin files|files]] and code patterns that all plugins have in common. Also there are specific interfaces that individual plugin types are expected to implement. When developing a new plugin, Moodle contributors use some available templates for various plugin types as well as existing plugins as a reference.&lt;br /&gt;
&lt;br /&gt;
The goal of this project is to develop a tool that helps Moodle contributors to generate a scaffold code for a new Moodle plugin. Given parameters such as plugin type, plugin name, list of enabled/disabled features and other meta-data (such as author name etc), the tool should generate a scaffold code for that plugin that the developer can build on.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Research and analysis of existing tools and approaches used in other software projects.&lt;br /&gt;
* Specification of the format/syntax of templates that will be used to generate the plugin code (consider Mustache as it is templating language that Moodle developers are most familiar with).&lt;br /&gt;
* Templates for all Moodle plugin types and specification of their storage, organisation and maintenance (so that it is possible to keep them up to date in further Moodle versions).&lt;br /&gt;
* Software tool that makes use of these templates and actually generates the plugin scaffold code.&lt;br /&gt;
&lt;br /&gt;
Requirements:&lt;br /&gt;
* The generated code should pass 100% of the Moodle codechecking tools to ensure it meets with Moodle Guidelines.&lt;br /&gt;
* The generator itself should be written in either PHP or JavaScript (Node.js) and provide both CLI and GUI.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP / Node.js, experience with Moodle plugins development is a big plus.&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add search to more moodle components ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. There are some module components, like glossary or databases that can use the search engine to index their data on it, so moodle users with permissions can access them quickly. This project would be about implementing the search API in some moodle components, the number of components can vary depending on the time available, but ideally this should land into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
=== Elastic search ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. The only search engine that will be initially supported will be solr, as elasticsearch has a good use base would be nice to write a search_elastic plugin implementing moodle&#039;s search engine API. This does not necessarily need to go into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;br /&gt;
* [[Projects for new developers/Archive|Archive]] of outdated and/or inactive calls for projects&lt;br /&gt;
* [https://docs.moodle.org/dev/Moodle_Wishlist a Wishlist] by some Moodle users. Some of the good ideas here may be adopted.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49399</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49399"/>
		<updated>2016-02-03T10:25:08Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Allow to crop/resize/rotate images when inserting them */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
&lt;br /&gt;
When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you complete the [http://dev.moodle.org/course/view.php?id=2 Introduction to Moodle Programming] course on [http://dev.moodle.org/ dev.moodle.org]. To access this you will need to have an account on moodle.org first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer]&#039;&#039;. See the [https://moodle.org/mod/forum/discuss.php?d=260354 Plugins adoption programme].&lt;br /&gt;
&lt;br /&gt;
As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Allow to crop/resize/rotate images when inserting them ===&lt;br /&gt;
&lt;br /&gt;
This project is inspired by MDL-52982 - the ability to alter an image via JS in atto.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: Javascript (YUI), PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/view.php?id=1057750 Mark Nelson]&lt;br /&gt;
&lt;br /&gt;
=== Improve Behat tests in SCORM plugin ===&lt;br /&gt;
The Moodle SCORM plugin does not contain very many behat tests and most tests are manual. The Claude Ostyn diagnostic SCO should be used to implement a range of new Behat tests to cover the functionality that the SCORM module provides.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Behat tests for all existing SCORM QA tests (where possible)&lt;br /&gt;
* Behat tests for all SCORM settings (eg standards mode, mastery score settings etc) &lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Advanced Grading in Forums ===&lt;br /&gt;
Finish the work required to add the advanced grading feature to the Moodle forum activity. This builds on some existing work available at MDL-31860&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Modify the forum grading so that it pushes 2 grade areas (or 3 including ratings) into the gradebook instead of a single grade.&lt;br /&gt;
* Improve interface that allows overall forum participation grading.&lt;br /&gt;
* Behat tests for all new functionality.&lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Add support to end-to-end testing in the Mobile app ===&lt;br /&gt;
&lt;br /&gt;
[https://angular.github.io/protractor/#/ Protractor] is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.&lt;br /&gt;
&lt;br /&gt;
The basements for this project are done, see MOBILE-1179, the only remaining work is to add more tests to the app and document the set-up process in the Moodle developers wiki.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (AngularJS)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Create a desktop version of Moodle Mobile using Electron ===&lt;br /&gt;
&lt;br /&gt;
[http://electron.atom.io/ Electron] is a tool for creating cross platform desktop applications using web technologies.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/moodlehq/moodlemobile/ Moodle Mobile 1] (the previous version of Moodle Mobile) had an experimental desktop application using a similar tool ([http://nwjs.io/ Node-Webkit, now NW.js]), for Moodle Mobile 2 we’d like to see the application packaged for desktop using Electron.&lt;br /&gt;
&lt;br /&gt;
In this project you will implement some of the Cordova APIs to use the Node.js API provided by electron:&lt;br /&gt;
* FileSystem API - For browsing the local file system&lt;br /&gt;
* FileTransfer API - For downloads and uploads&lt;br /&gt;
* Camera and capture API - For taking photos, videos and audios using the webcam&lt;br /&gt;
&lt;br /&gt;
Notice that these APIs are already implemented in the previous version of Moodle Mobile 1, this project is about migrating this old APIs from Node-Webkit to the new version of the application using Electron.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (Node.js)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Generator of Moodle plugins scaffold code ===&lt;br /&gt;
&lt;br /&gt;
There are many [[Plugin types|plugin types]] in Moodle. There are [[Plugin files|files]] and code patterns that all plugins have in common. Also there are specific interfaces that individual plugin types are expected to implement. When developing a new plugin, Moodle contributors use some available templates for various plugin types as well as existing plugins as a reference.&lt;br /&gt;
&lt;br /&gt;
The goal of this project is to develop a tool that helps Moodle contributors to generate a scaffold code for a new Moodle plugin. Given parameters such as plugin type, plugin name, list of enabled/disabled features and other meta-data (such as author name etc), the tool should generate a scaffold code for that plugin that the developer can build on.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Research and analysis of existing tools and approaches used in other software projects.&lt;br /&gt;
* Specification of the format/syntax of templates that will be used to generate the plugin code (consider Mustache as it is templating language that Moodle developers are most familiar with).&lt;br /&gt;
* Templates for all Moodle plugin types and specification of their storage, organisation and maintenance (so that it is possible to keep them up to date in further Moodle versions).&lt;br /&gt;
* Software tool that makes use of these templates and actually generates the plugin scaffold code.&lt;br /&gt;
&lt;br /&gt;
Requirements:&lt;br /&gt;
* The generated code should pass 100% of the Moodle codechecking tools to ensure it meets with Moodle Guidelines.&lt;br /&gt;
* The generator itself should be written in either PHP or JavaScript (Node.js) and provide both CLI and GUI.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP / Node.js, experience with Moodle plugins development is a big plus.&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add search to more moodle components ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. There are some module components, like glossary or databases that can use the search engine to index their data on it, so moodle users with permissions can access them quickly. This project would be about implementing the search API in some moodle components, the number of components can vary depending on the time available, but ideally this should land into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
=== Elastic search ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. The only search engine that will be initially supported will be solr, as elasticsearch has a good use base would be nice to write a search_elastic plugin implementing moodle&#039;s search engine API. This does not necessarily need to go into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;br /&gt;
* [[Projects for new developers/Archive|Archive]] of outdated and/or inactive calls for projects&lt;br /&gt;
* [https://docs.moodle.org/dev/Moodle_Wishlist a Wishlist] by some Moodle users. Some of the good ideas here may be adopted.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49398</id>
		<title>Projects for new developers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Projects_for_new_developers&amp;diff=49398"/>
		<updated>2016-02-03T10:22:11Z</updated>

		<summary type="html">&lt;p&gt;Markn: /* Allow to crop/resize/rotate images when inserting them */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{GSOC}}&lt;br /&gt;
&lt;br /&gt;
==Getting started==&lt;br /&gt;
&lt;br /&gt;
Moodle uses PHP, JavaScript, SQL and a number of other Web languages, so learning those is a good place to start.&lt;br /&gt;
&lt;br /&gt;
When you have some basic PHP programming skills, you may wish to start learning about how the Moodle code is organised. It is recommended that you complete the [http://dev.moodle.org/course/view.php?id=2 Introduction to Moodle Programming] course on [http://dev.moodle.org/ dev.moodle.org]. To access this you will need to have an account on moodle.org first.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking for projects suggested in the tracker, look for issues with the [https://tracker.moodle.org/issues/?jql=labels%20in%20%28addon_candidate%29 &#039;addon_candidate&#039; label].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you are looking to make a quick contribution, look for tracker issues with marked as [https://tracker.moodle.org/issues/?jql=Difficulty%20%3D%20Easy easy].&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;Please consider adopting a [https://moodle.org/plugins/browse.php?list=set&amp;amp;id=61 plugin seeking a new maintainer]&#039;&#039;. See the [https://moodle.org/mod/forum/discuss.php?d=260354 Plugins adoption programme].&lt;br /&gt;
&lt;br /&gt;
As you become more involved in Moodle development, you might like to learn more about the [[Coding|coding conventions]] used and how changes to Moodle core code are [[Process|processed]].&lt;br /&gt;
&lt;br /&gt;
==Potential projects==&lt;br /&gt;
&lt;br /&gt;
This evolving page lists possible Moodle projects for new developers derived from community suggestions.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;If you have any ideas for new features in Moodle which might be suitable as projects for new developers, please see [[New feature ideas]].&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
=== Allow to crop/resize/rotate images when inserting them ===&lt;br /&gt;
&lt;br /&gt;
This project is inspired by MDL-52982 - the ability to alter an image via JS in atto.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: Javascript (YUI), PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;:&lt;br /&gt;
&lt;br /&gt;
=== Improve Behat tests in SCORM plugin ===&lt;br /&gt;
The Moodle SCORM plugin does not contain very many behat tests and most tests are manual. The Claude Ostyn diagnostic SCO should be used to implement a range of new Behat tests to cover the functionality that the SCORM module provides.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Behat tests for all existing SCORM QA tests (where possible)&lt;br /&gt;
* Behat tests for all SCORM settings (eg standards mode, mastery score settings etc) &lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Advanced Grading in Forums ===&lt;br /&gt;
Finish the work required to add the advanced grading feature to the Moodle forum activity. This builds on some existing work available at MDL-31860&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Modify the forum grading so that it pushes 2 grade areas (or 3 including ratings) into the gradebook instead of a single grade.&lt;br /&gt;
* Improve interface that allows overall forum participation grading.&lt;br /&gt;
* Behat tests for all new functionality.&lt;br /&gt;
* The code should pass 100% of the Moodle codechecking tools to ensure the code meets with Moodle Guidelines.&lt;br /&gt;
&lt;br /&gt;
Extra requirement for prospective students:&lt;br /&gt;
* We require prospective students to make an attempt at fixing at least 1 issue in the Moodle tracker before their proposal can be considered - on top of this you must also attempt to convert one existing QA test into a Behat test. This MUST be completed before your application can be considered valid. If you do not have time to do this before the submission deadline your application will not be considered.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required&#039;&#039;&#039;: PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=21591&amp;amp;course=5 Dan Marsden]&lt;br /&gt;
&lt;br /&gt;
=== Add support to end-to-end testing in the Mobile app ===&lt;br /&gt;
&lt;br /&gt;
[https://angular.github.io/protractor/#/ Protractor] is an end-to-end test framework for AngularJS applications. Protractor runs tests against your application running in a real browser, interacting with it as a user would.&lt;br /&gt;
&lt;br /&gt;
The basements for this project are done, see MOBILE-1179, the only remaining work is to add more tests to the app and document the set-up process in the Moodle developers wiki.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (AngularJS)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Create a desktop version of Moodle Mobile using Electron ===&lt;br /&gt;
&lt;br /&gt;
[http://electron.atom.io/ Electron] is a tool for creating cross platform desktop applications using web technologies.&lt;br /&gt;
&lt;br /&gt;
[https://github.com/moodlehq/moodlemobile/ Moodle Mobile 1] (the previous version of Moodle Mobile) had an experimental desktop application using a similar tool ([http://nwjs.io/ Node-Webkit, now NW.js]), for Moodle Mobile 2 we’d like to see the application packaged for desktop using Electron.&lt;br /&gt;
&lt;br /&gt;
In this project you will implement some of the Cordova APIs to use the Node.js API provided by electron:&lt;br /&gt;
* FileSystem API - For browsing the local file system&lt;br /&gt;
* FileTransfer API - For downloads and uploads&lt;br /&gt;
* Camera and capture API - For taking photos, videos and audios using the webcam&lt;br /&gt;
&lt;br /&gt;
Notice that these APIs are already implemented in the previous version of Moodle Mobile 1, this project is about migrating this old APIs from Node-Webkit to the new version of the application using Electron.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required: Javascript (Node.js)&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor: [https://moodle.org/user/profile.php?id=49568 Juan Leyva]&lt;br /&gt;
&lt;br /&gt;
=== Generator of Moodle plugins scaffold code ===&lt;br /&gt;
&lt;br /&gt;
There are many [[Plugin types|plugin types]] in Moodle. There are [[Plugin files|files]] and code patterns that all plugins have in common. Also there are specific interfaces that individual plugin types are expected to implement. When developing a new plugin, Moodle contributors use some available templates for various plugin types as well as existing plugins as a reference.&lt;br /&gt;
&lt;br /&gt;
The goal of this project is to develop a tool that helps Moodle contributors to generate a scaffold code for a new Moodle plugin. Given parameters such as plugin type, plugin name, list of enabled/disabled features and other meta-data (such as author name etc), the tool should generate a scaffold code for that plugin that the developer can build on.&lt;br /&gt;
&lt;br /&gt;
Deliverables:&lt;br /&gt;
* Research and analysis of existing tools and approaches used in other software projects.&lt;br /&gt;
* Specification of the format/syntax of templates that will be used to generate the plugin code (consider Mustache as it is templating language that Moodle developers are most familiar with).&lt;br /&gt;
* Templates for all Moodle plugin types and specification of their storage, organisation and maintenance (so that it is possible to keep them up to date in further Moodle versions).&lt;br /&gt;
* Software tool that makes use of these templates and actually generates the plugin scaffold code.&lt;br /&gt;
&lt;br /&gt;
Requirements:&lt;br /&gt;
* The generated code should pass 100% of the Moodle codechecking tools to ensure it meets with Moodle Guidelines.&lt;br /&gt;
* The generator itself should be written in either PHP or JavaScript (Node.js) and provide both CLI and GUI.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP / Node.js, experience with Moodle plugins development is a big plus.&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [http://moodle.org/user/view.php?id=1601&amp;amp;course=5 David Mudrák]&lt;br /&gt;
&lt;br /&gt;
=== Add search to more moodle components ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. There are some module components, like glossary or databases that can use the search engine to index their data on it, so moodle users with permissions can access them quickly. This project would be about implementing the search API in some moodle components, the number of components can vary depending on the time available, but ideally this should land into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
=== Elastic search ===&lt;br /&gt;
&lt;br /&gt;
MDL-31989 is introducing global search to Moodle to index moodle data in an external source and to retrieve data back from that external source. The only search engine that will be initially supported will be solr, as elasticsearch has a good use base would be nice to write a search_elastic plugin implementing moodle&#039;s search engine API. This does not necessarily need to go into core.&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;Skills required:&#039;&#039;&#039; PHP&lt;br /&gt;
:&#039;&#039;&#039;Difficulty level&#039;&#039;&#039;: Medium&lt;br /&gt;
:&#039;&#039;&#039;Possible mentor&#039;&#039;&#039;: [https://moodle.org/user/profile.php?id=122326 David Monllao]&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
&lt;br /&gt;
* [[GSOC]] - describing Moodle&#039;s involvement with Google in their Summer of Code program&lt;br /&gt;
* [https://tracker.moodle.org/issues/?jql=type%20in%20%28%22New%20Feature%22%2C%20Improvement%29%20AND%20resolution%20%3D%20unresolved%20and%20labels%20in%20%28addon_candidate%29%20ORDER%20BY%20votes%20DESC Popular new feature and improvement requests in Tracker that can be implemented as plugins]&lt;br /&gt;
* [[Projects for new developers/Archive|Archive]] of outdated and/or inactive calls for projects&lt;br /&gt;
* [https://docs.moodle.org/dev/Moodle_Wishlist a Wishlist] by some Moodle users. Some of the good ideas here may be adopted.&lt;/div&gt;</summary>
		<author><name>Markn</name></author>
	</entry>
</feed>