<?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=Plemaire</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=Plemaire"/>
	<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/Special:Contributions/Plemaire"/>
	<updated>2026-04-13T10:24:51Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.5</generator>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Message_API&amp;diff=59002</id>
		<title>Message API</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Message_API&amp;diff=59002"/>
		<updated>2021-06-26T13:08:35Z</updated>

		<summary type="html">&lt;p&gt;Plemaire: /* Changes in Moodle 3.5 */ very small correction&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==What is this document?==&lt;br /&gt;
&lt;br /&gt;
This document describes how to make use of the Moodle Messaging API to send messages to Moodle users.&lt;br /&gt;
&lt;br /&gt;
If you are after a general introduction on using the Moodle Messaging system go to [[:en:Messaging|messaging user documentation]].&lt;br /&gt;
&lt;br /&gt;
If you are looking for details of how the Messaging system&#039;s internal structure was implemented, go to [[Messaging 2.0]].&lt;br /&gt;
&lt;br /&gt;
If you are looking for instructions on the implementation of a custom message processor (a component that receives messages sent to a user), go to [[Messaging custom components]].&lt;br /&gt;
&lt;br /&gt;
If you are looking for instructions on sending messages programatically within Moodle then read on...&lt;br /&gt;
&lt;br /&gt;
==Overview==&lt;br /&gt;
&lt;br /&gt;
Moodle components have the ability to send messages to users via the Moodle messaging system. Any type of component, for example a plugin or block, can register as a message producer then send messages to users.&lt;br /&gt;
&lt;br /&gt;
==File locations==&lt;br /&gt;
&lt;br /&gt;
The Message API code is contained within lib/messagelib.php and is automatically included for you during page setup.&lt;br /&gt;
&lt;br /&gt;
==Functions==&lt;br /&gt;
&lt;br /&gt;
message_send() is the primary point of contact for the message API. Call it to send a message to a user. You can find a full description of the arguments that must be supplied at (link to phpdocs). There is also an example below.&lt;br /&gt;
&lt;br /&gt;
==Message popup==&lt;br /&gt;
{{Moodle_2.9}}&lt;br /&gt;
A Javascript popup can be displayed through a link to invite a user to message another. In order to use this feature, you need to require the Javascript libraries using &#039;&#039;message_messenger_requirejs()&#039;&#039; and create a link with the attributes returned by &#039;&#039;message_messenger_sendmessage_link_params()&#039;&#039;. More in the examples.&lt;br /&gt;
&lt;br /&gt;
==Examples==&lt;br /&gt;
&lt;br /&gt;
===How to register as a message producer===&lt;br /&gt;
&lt;br /&gt;
The messages produced by a message provider is defined in the /db/messages.php file of a component. Below is code from the quiz module&#039;s messages.php file, shown as an example.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
defined(&#039;MOODLE_INTERNAL&#039;) || die();&lt;br /&gt;
$messageproviders = array (&lt;br /&gt;
    // Notify teacher that a student has submitted a quiz attempt&lt;br /&gt;
    &#039;submission&#039; =&amp;gt; array (&lt;br /&gt;
        &#039;capability&#039;  =&amp;gt; &#039;mod/quiz:emailnotifysubmission&#039;&lt;br /&gt;
    ),&lt;br /&gt;
    // Confirm a student&#039;s quiz attempt&lt;br /&gt;
    &#039;confirmation&#039; =&amp;gt; array (&lt;br /&gt;
        &#039;capability&#039;  =&amp;gt; &#039;mod/quiz:emailconfirmsubmission&#039;&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The quiz can send two kinds of messages, quiz &amp;quot;submission&amp;quot; and &amp;quot;confirmation&amp;quot; notifications. Each message type is only available to users with the appropriate capability. Please note that the capability is checked at the system level context. Users who have this capability will have this message listed in their messaging preferences. You can omit the capability section if your message should be visible for all users. For example forum post notifications are available to all users.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$messageproviders = array (&lt;br /&gt;
    // Ordinary single forum posts&lt;br /&gt;
    &#039;posts&#039; =&amp;gt; array (&lt;br /&gt;
    )&lt;br /&gt;
);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When displaying your message types in a user&#039;s messaging preferences it will use a string from your component&#039;s language file called &amp;quot;messageprovider:messagename&amp;quot;. For example here are the relevant strings from the quiz&#039;s language file.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$string[&#039;messageprovider:confirmation&#039;] = &#039;Confirmation of your own quiz submissions&#039;;&lt;br /&gt;
$string[&#039;messageprovider:submission&#039;] = &#039;Notification of quiz submissions&#039;;&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Once your messages.php is complete you need to increase the version number of your component in its version.php. That will cause Moodle to check messages.php looking for new or changed message definitions. Log in as an admin and go to /admin/index.php (the Notifications page) to start the upgrade process.&lt;br /&gt;
===Setting defaults===&lt;br /&gt;
The default processor can be set using an element of the array &lt;br /&gt;
e.g.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
 &#039;mynotification&#039; =&amp;gt; [&lt;br /&gt;
         &#039;defaults&#039; =&amp;gt; [&lt;br /&gt;
              &#039;popup&#039; =&amp;gt; MESSAGE_PERMITTED + MESSAGE_DEFAULT_LOGGEDIN + MESSAGE_DEFAULT_LOGGEDOFF,&lt;br /&gt;
              &#039;email&#039; =&amp;gt; MESSAGE_PERMITTED &lt;br /&gt;
          ],&lt;br /&gt;
    ],&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
With that setting email will be permitted but disabled for each user by default. It  can be turned on by each user through the preferences/notification preferences options (/message/notificationpreferences.php?userid=X)&lt;br /&gt;
The possible values are recorded in the lib.php file of messaging&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
/**&lt;br /&gt;
 * Define contants for messaging default settings population. For unambiguity of&lt;br /&gt;
 * plugin developer intentions we use 4-bit value (LSB numbering):&lt;br /&gt;
 * bit 0 - whether to send message when user is loggedin (MESSAGE_DEFAULT_LOGGEDIN)&lt;br /&gt;
 * bit 1 - whether to send message when user is loggedoff (MESSAGE_DEFAULT_LOGGEDOFF)&lt;br /&gt;
 * bit 2..3 - messaging permission (MESSAGE_DISALLOWED|MESSAGE_PERMITTED|MESSAGE_FORCED)&lt;br /&gt;
 *&lt;br /&gt;
 * MESSAGE_PERMITTED_MASK contains the mask we use to distinguish permission setting&lt;br /&gt;
 */&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
Note that if you change the values in message.php and then upgrade the plugin the values will not automatically be changed in the config_plugins table where they are stored.&lt;br /&gt;
&lt;br /&gt;
===How to send a message===&lt;br /&gt;
{{Moodle_2.9}}&lt;br /&gt;
Here is example code showing you how to actually send a notification message. The example shows the construction of a object with specific properties, which is then passed to the message_send() function that uses the information to send a message.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$message = new \core\message\message();&lt;br /&gt;
$message-&amp;gt;component = &#039;mod_yourmodule&#039;; // Your plugin&#039;s name&lt;br /&gt;
$message-&amp;gt;name = &#039;mynotification&#039;; // Your notification name from message.php&lt;br /&gt;
$message-&amp;gt;userfrom = core_user::get_noreply_user(); // If the message is &#039;from&#039; a specific user you can set them here&lt;br /&gt;
$message-&amp;gt;userto = $user;&lt;br /&gt;
$message-&amp;gt;subject = &#039;message subject 1&#039;;&lt;br /&gt;
$message-&amp;gt;fullmessage = &#039;message body&#039;;&lt;br /&gt;
$message-&amp;gt;fullmessageformat = FORMAT_MARKDOWN;&lt;br /&gt;
$message-&amp;gt;fullmessagehtml = &#039;&amp;lt;p&amp;gt;message body&amp;lt;/p&amp;gt;&#039;;&lt;br /&gt;
$message-&amp;gt;smallmessage = &#039;small message&#039;;&lt;br /&gt;
$message-&amp;gt;notification = 1; // Because this is a notification generated from Moodle, not a user-to-user message&lt;br /&gt;
$message-&amp;gt;contexturl = (new \moodle_url(&#039;/course/&#039;))-&amp;gt;out(false); // A relevant URL for the notification&lt;br /&gt;
$message-&amp;gt;contexturlname = &#039;Course list&#039;; // Link title explaining where users get to for the contexturl&lt;br /&gt;
$content = array(&#039;*&#039; =&amp;gt; array(&#039;header&#039; =&amp;gt; &#039; test &#039;, &#039;footer&#039; =&amp;gt; &#039; test &#039;)); // Extra content for specific processor&lt;br /&gt;
$message-&amp;gt;set_additional_content(&#039;email&#039;, $content);&lt;br /&gt;
&lt;br /&gt;
// You probably don&#039;t need attachments but if you do, here is how to add one&lt;br /&gt;
$usercontext = context_user::instance($user-&amp;gt;id);&lt;br /&gt;
$file = new stdClass;&lt;br /&gt;
$file-&amp;gt;contextid = $usercontext-&amp;gt;id;&lt;br /&gt;
$file-&amp;gt;component = &#039;user&#039;;&lt;br /&gt;
$file-&amp;gt;filearea  = &#039;private&#039;;&lt;br /&gt;
$file-&amp;gt;itemid    = 0;&lt;br /&gt;
$file-&amp;gt;filepath  = &#039;/&#039;;&lt;br /&gt;
$file-&amp;gt;filename  = &#039;1.txt&#039;;&lt;br /&gt;
$file-&amp;gt;source    = &#039;test&#039;;&lt;br /&gt;
&lt;br /&gt;
$fs = get_file_storage();&lt;br /&gt;
$file = $fs-&amp;gt;create_file_from_string($file, &#039;file1 content&#039;);&lt;br /&gt;
$message-&amp;gt;attachment = $file;&lt;br /&gt;
&lt;br /&gt;
// Actually send the message&lt;br /&gt;
$messageid = message_send($message);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Before 2.9 message data used to be a stdClass object as shown below (This formation of a message will no longer work as of Moodle 3.6. Only a message object will be accepted):-&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$message = new stdClass();&lt;br /&gt;
$message-&amp;gt;component         = &#039;mod_quiz&#039;; //your component name&lt;br /&gt;
$message-&amp;gt;name              = &#039;submission&#039;; //this is the message name from messages.php&lt;br /&gt;
$message-&amp;gt;userfrom          = $USER;&lt;br /&gt;
$message-&amp;gt;userto            = $touser;&lt;br /&gt;
$message-&amp;gt;subject           = $subject;&lt;br /&gt;
$message-&amp;gt;fullmessage       = $message;&lt;br /&gt;
$message-&amp;gt;fullmessageformat = FORMAT_PLAIN;&lt;br /&gt;
$message-&amp;gt;fullmessagehtml   = &#039;&#039;;&lt;br /&gt;
$message-&amp;gt;smallmessage      = &#039;&#039;;&lt;br /&gt;
$message-&amp;gt;notification      = 1; //this is only set to 0 for personal messages between users&lt;br /&gt;
message_send($message);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===How to set-up the message popup===&lt;br /&gt;
&lt;br /&gt;
Here is example code showing you how to set-up the Javascript popup link.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
require_once(&#039;message/lib.php&#039;);&lt;br /&gt;
$userid = 2;&lt;br /&gt;
$userto = $DB-&amp;gt;get_record(&#039;user&#039;, array(&#039;id&#039; =&amp;gt; $userid));&lt;br /&gt;
&lt;br /&gt;
message_messenger_requirejs();&lt;br /&gt;
$url = new moodle_url(&#039;message/index.php&#039;, array(&#039;id&#039; =&amp;gt; $userto-&amp;gt;id));&lt;br /&gt;
$attributes = message_messenger_sendmessage_link_params($userto);&lt;br /&gt;
echo html_writer::link($url, &#039;Send a message&#039;, $attributes);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Changes in Moodle 3.5==&lt;br /&gt;
{{Moodle_3.5}}&lt;br /&gt;
&lt;br /&gt;
In Moodle 3.5, there were some moderately big changes. The only docs I have been able to find about them are in [https://github.com/moodle/moodle/blob/33a388eff737c049786ee42d7430db549568471c/message/upgrade.txt#L56 upgrade.txt] file. However, that is the details, here is an overview:&lt;br /&gt;
&lt;br /&gt;
The main message_send() API to send a message has not changed, so if your code is just sending messages, you don&#039;t need to do anything.&lt;br /&gt;
&lt;br /&gt;
Similarly, message_output plugins don&#039;t need to change, so no worries there.&lt;br /&gt;
&lt;br /&gt;
If you are doing things with messages, then you need to understand how the internals have changed.&lt;br /&gt;
&lt;br /&gt;
The database tables have changed. Messages from Moodle components to a user (e.g. mod_quiz), telling them that something has happened (e.g. an attempt was submitted) have always been &#039;Notifications&#039;. In the past, this was just a column in the mdl_message table. Now, messages and notifications are stored in completely separate tables. Notifications are in mdl_notifications. The strucutre of this table is very similar to the old mdl_message table which is now not used at all. Messages are in mdl_messages, and related tables, that now exist to support group messaging. Those tables join together like this:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code sql&amp;gt;&lt;br /&gt;
SELECT *&lt;br /&gt;
&lt;br /&gt;
FROM mdl_messages m&lt;br /&gt;
JOIN mdl_message_conversations con ON con.id = m.conversationid&lt;br /&gt;
JOIN mdl_message_conversation_members mem ON mem.conversationid = con.id&lt;br /&gt;
LEFT JOIN mdl_message_user_actions act ON act.userid = mem.userid AND act.messageid = m.id&lt;br /&gt;
&lt;br /&gt;
ORDER BY m.timecreated, m.id, mem.userid, act.id&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==See also==&lt;br /&gt;
* [[Core APIs]]&lt;br /&gt;
&lt;br /&gt;
[[Category:API]]&lt;br /&gt;
[[Category:Tutorial]]&lt;br /&gt;
[[Category:Plugins]]&lt;br /&gt;
[[Category:Messaging]]&lt;/div&gt;</summary>
		<author><name>Plemaire</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Output_renderers&amp;diff=57282</id>
		<title>Output renderers</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Output_renderers&amp;diff=57282"/>
		<updated>2020-04-11T18:25:45Z</updated>

		<summary type="html">&lt;p&gt;Plemaire: typographical error&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Work in progress}}&lt;br /&gt;
{{Infobox Project&lt;br /&gt;
|name = Output renderers&lt;br /&gt;
|state = Implemented&lt;br /&gt;
|tracker = MDL-21235&lt;br /&gt;
|discussion = n/a&lt;br /&gt;
|assignee = [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]] + [[User:David Mudrak|David Mudrak]] + feedback and ideas from other developers&lt;br /&gt;
}}&lt;br /&gt;
{{Moodle 2.0}}&lt;br /&gt;
&lt;br /&gt;
== Goals ==&lt;br /&gt;
* stable API&lt;br /&gt;
* easy to use&lt;br /&gt;
* easy to customise via themes&lt;br /&gt;
&lt;br /&gt;
== Renderers ==&lt;br /&gt;
&lt;br /&gt;
Output renderer is a class with collection of methods that handle rendering of visual aspects of Moodle pages, emails, html export, etc. In Moodle 1.9, general output related functions were located in weblib.php and modules stored rendering code in lib.php, locallib.php, view.php, etc. Output renderer instances are obtained through moodle_page::get_renderer($component, $subtype = null, $target = null) method.&lt;br /&gt;
&lt;br /&gt;
The general renderer class naming convention is:&lt;br /&gt;
 {theme name}_{plugin type}_{plugin_name}_{subtype}_renderer_{target}&lt;br /&gt;
&lt;br /&gt;
or (if using namespaces)&lt;br /&gt;
&lt;br /&gt;
 \{plugin type}_{plugin name}\output\{subtype}_renderer_{target} (standard plugin renderer)&lt;br /&gt;
&lt;br /&gt;
 \theme_{theme name}\output\{plugin type}_{plugin name}\{subtype}_renderer_{target} (plugin renderer overridden in a theme)&lt;br /&gt;
&lt;br /&gt;
where theme name prefix, subtype infix and target suffix are optional. Examples of renderer class name are core_renderer, mytheme_core_renderer, mod_workshop_renderer, mod_forum_renderer_cli, \tool_templatelibrary\output\renderer etc.&lt;br /&gt;
&lt;br /&gt;
; Renderer subtype : When get_renderer() is called, $subtype parameter can be provided to obtain a different renderer. Renderer subtypes are used mainly for core subsystems, but it is also possible to use them in modules.&lt;br /&gt;
&lt;br /&gt;
; Renderer targets : In most cases, we are rendering page output for web browsers. Sometimes we need to generate different output for command line scripts, email messages, etc. When get_renderer() is called, $target parameter can be provided to obtain a different renderer. The list of targets will be part of the specification, individual plugins should not invent new rendering targets.&lt;br /&gt;
&lt;br /&gt;
: note that both $subtype and $target works similarly - they just influence the name of the class to be returned by get_renderer(). But there is semantic difference and we will probably have the list of allowed targets limited (defaults to html).&lt;br /&gt;
&lt;br /&gt;
== Overall picture ==&lt;br /&gt;
&lt;br /&gt;
The following UML diagram describes the main classes involved in HTML output rendering and their relationships.&lt;br /&gt;
&lt;br /&gt;
[[Image:uml_output_renderers.png|800px|left]] [[Media:uml_output_renderers.dia|(dia source)]]&lt;br /&gt;
&amp;lt;br clear=&amp;quot;both&amp;quot; /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== renderer_base ===&lt;br /&gt;
&lt;br /&gt;
Abstract class every other renderer must extend. Renderer base implements basic methods and support for renderer dispatching.&lt;br /&gt;
&lt;br /&gt;
=== core_renderer ===&lt;br /&gt;
&lt;br /&gt;
Current core_renderer is available through the global $OUTPUT variable. This global should not be used in lower level APIs - only in the main scripts like view.php. When you want to start to print something, you will probably call&lt;br /&gt;
 echo $OUTPUT-&amp;gt;header();&lt;br /&gt;
in your view.php or similar script. To print a page footer and terminate your PHP script, you will call&lt;br /&gt;
 echo $OUTPUT-&amp;gt;footer();&lt;br /&gt;
 die();&lt;br /&gt;
&lt;br /&gt;
Beside these page header and footer related things, core_renderer knows how to display&lt;br /&gt;
# boxes and containers - basically &amp;amp;lt;div&amp;amp;gt; elements&lt;br /&gt;
# general widgets - headings, single buttons, selection forms, arrows in the breadcrumb navigation, language selection popup, user login info etc.&lt;br /&gt;
# error messages, notifications&lt;br /&gt;
# blocks&lt;br /&gt;
&lt;br /&gt;
=== method render() and interface renderable ===&lt;br /&gt;
&lt;br /&gt;
Various widgets (headings, buttons etc.) and other content blocks (submissions, forum posts etc.) are represented as classes. In most cases, they will look like a simple object with just some properties and a constructor to set the most common ones. Core renderer implements protected methods to render these widgets. These widget rendering methods are called render_something() where &#039;&#039;something&#039;&#039; is the name of the widget. Their first parameter must be an instance of &#039;&#039;something&#039;&#039; class that implements interface &#039;&#039;renderable&#039;&#039;. These methods can be overridden by themes.&lt;br /&gt;
&lt;br /&gt;
Public method to render a widget is called render(). It accepts the only parameter which must be an instance of a class implementing &#039;&#039;renderable&#039;&#039; interface. It uses the class name of the widget passed in as parameter to find the corresponding protected rendering method.&lt;br /&gt;
&lt;br /&gt;
If the widget also implements the &amp;quot;templatable&amp;quot; interface, and there is no render_widget helper explicitly defined for this class, then the render method will look for a template name matching the class in the same component. If found, it will automatically render the template with the data exported using $widget-&amp;gt;export_for_template(), no additional renderer code is required.&lt;br /&gt;
&lt;br /&gt;
Implementation of renderer_base::render() (inherited by all renderers)&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class renderer_base {&lt;br /&gt;
    // ...&lt;br /&gt;
   public function render(renderable $widget) {&lt;br /&gt;
        $classparts = explode(&#039;\\&#039;, get_class($widget));&lt;br /&gt;
        // Strip namespaces.&lt;br /&gt;
        $classname = array_pop($classparts);&lt;br /&gt;
        // Remove _renderable suffixes&lt;br /&gt;
        $classname = preg_replace(&#039;/_renderable$/&#039;, &#039;&#039;, $classname);&lt;br /&gt;
&lt;br /&gt;
        $rendermethod = &#039;render_&#039;.$classname;&lt;br /&gt;
        if (method_exists($this, $rendermethod)) {&lt;br /&gt;
            return $this-&amp;gt;$rendermethod($widget);&lt;br /&gt;
        }&lt;br /&gt;
        if ($widget instanceof templatable) {&lt;br /&gt;
            $component = array_shift($classparts);&lt;br /&gt;
            if (!$component) {&lt;br /&gt;
                $component = &#039;core&#039;;&lt;br /&gt;
            }&lt;br /&gt;
            $template = $component . &#039;/&#039; . $classname;&lt;br /&gt;
            $context = $widget-&amp;gt;export_for_template($this);&lt;br /&gt;
            return $this-&amp;gt;render_from_template($template, $context);&lt;br /&gt;
        }&lt;br /&gt;
        throw new coding_exception(&#039;Can not render widget, renderer method (&#039;.$rendermethod.&#039;) not found.&#039;);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
For some widgets, a helper method may be implemented to instantiate the widget and render it in the background. Such helper methods have the same name as the widget class and accepts parameters needed to create the widget instance. Themes should not override helper methods because their usage is optional.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039; User avatar rendering involves following methods and classes:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
class core_renderer extends renderer_base {&lt;br /&gt;
    // ...&lt;br /&gt;
    protected function render_user_picture(user_picture $userpicture) {&lt;br /&gt;
        // returns HTML code to be echoed for displaying the user avatar&lt;br /&gt;
    }&lt;br /&gt;
    public function user_picture(stdclass $userrecord, array $options=null) {&lt;br /&gt;
        // helper method that constructs $user_image widget and calls $this-&amp;gt;render()&lt;br /&gt;
        $picture = new user_picture($userrecord, $options);&lt;br /&gt;
        return $this-&amp;gt;render($picture);&lt;br /&gt;
    }&lt;br /&gt;
    // ...&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
class user_picture implements renderable {&lt;br /&gt;
    public $userrecord;&lt;br /&gt;
    public $courseid = 0;&lt;br /&gt;
    public $link = true;&lt;br /&gt;
&lt;br /&gt;
    public function __construct(stdclass $userrecord, array $options=null) {&lt;br /&gt;
        // ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
There are two ways a developer can render the user picture. Either using a one-line style:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$user = $DB-&amp;gt;get_record(&#039;user&#039;, array(...));&lt;br /&gt;
echo $OUTPUT-&amp;gt;user_picture($user, array(&#039;courseid&#039; =&amp;gt; $courseid, &#039;link&#039; =&amp;gt; true));&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
or an explicit style:&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$user = $DB-&amp;gt;get_record(&#039;user&#039;, array(...));&lt;br /&gt;
$avatar = new user_picture($user);&lt;br /&gt;
$avatar-&amp;gt;courseid = $courseid;&lt;br /&gt;
$avatar-&amp;gt;link = true;&lt;br /&gt;
echo $OUTPUT-&amp;gt;render($avatar);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The point is that the first style is usually one line only, it is also possible to have multiple helpers with different parameters. The second style allows more options without cluttering the simple API with tons of optional method parameters.&lt;br /&gt;
&lt;br /&gt;
Plugins can also use renderable objects and define render_something() functions in plugin renderers.&lt;br /&gt;
&lt;br /&gt;
=== core_renderer_cli ===&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;_cli&#039;&#039; suffix indicates this is a core renderer for CLI rendering target (CLI scripts). For example headings are using &#039;&#039;&#039;=&amp;gt;&#039;&#039;&#039; instead if H2 html tag.&lt;br /&gt;
&lt;br /&gt;
== Core subsystem renderers ==&lt;br /&gt;
&lt;br /&gt;
== Plugin renderers ==&lt;br /&gt;
&lt;br /&gt;
Plugin renderers are stored in renderer.php file in the root folder of the plugin or in /classes/. They all extend plugin_renderer_base method.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== plugin_renderer_base ===&lt;br /&gt;
&lt;br /&gt;
An important thing about this class is that it keeps a reference to an instance of (typically) core_renderer which is used as an underlying renderer. This reference is kept in protected $output member variable. So, there is no more $OUTPUT in plugin renderers. They all use $this-&amp;gt;output-&amp;gt;something() to render the output.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Example:&#039;&#039;&#039; Workshop module defines mod_workshop_renderer class in mod/workshop/renderer.php file. The renderer defines a method to display a student submission.&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
// in renderer.php:&lt;br /&gt;
class workshop_submission implements renderable {&lt;br /&gt;
&lt;br /&gt;
    public function __construct(stdclass $submission, $anonymous = false, array $attachments = null) {&lt;br /&gt;
        // here the widget is prepared and all necessary logic is performed&lt;br /&gt;
        if ($anonymous) {&lt;br /&gt;
            $this-&amp;gt;authorname = get_string(&#039;anonymousauthor&#039;, &#039;workshop&#039;);&lt;br /&gt;
        } else {&lt;br /&gt;
            $this-&amp;gt;authorname = fullname(...);&lt;br /&gt;
        }&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
class mod_workshop_renderer extends plugin_renderer_base {&lt;br /&gt;
&lt;br /&gt;
    protected function render_workshop_submission(workshop_submission $submission) {&lt;br /&gt;
        $out  = $this-&amp;gt;output-&amp;gt;heading(format_string($submission-&amp;gt;title), 2);&lt;br /&gt;
        $out .= $this-&amp;gt;output-&amp;gt;container(format_string($submission-&amp;gt;authorname), &#039;author&#039;);&lt;br /&gt;
        $out .= $this-&amp;gt;output-&amp;gt;container(format_text($submission-&amp;gt;content, FORMAT_HTML), &#039;content&#039;);&lt;br /&gt;
        return $this-&amp;gt;output-&amp;gt;container($out, &#039;submission&#039;);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
// in view.php&lt;br /&gt;
$output = $PAGE-&amp;gt;get_renderer(&#039;mod_workshop&#039;);&lt;br /&gt;
$submissionrecord = get_record(&#039;workshop_submissions&#039;, array(...));&lt;br /&gt;
$submissionwidget = new workshop_submission($submissionrecord, false);&lt;br /&gt;
echo $output-&amp;gt;header();&lt;br /&gt;
echo $output-&amp;gt;render($submissionwidget);&lt;br /&gt;
echo $output-&amp;gt;footer();&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that $output-&amp;gt;header() and $output-&amp;gt;footer() are not defined in mod_workshop_renderer. Plugin renderers are able to forward calls to the underlying renderer automatically. So, in view.php, there could be echo $OUTPUT-&amp;gt;header(); which would call the same method. We prefer the way above because of consistency - there is the only one $output instance used instead of two $OUTPUT and $wsoutput.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;WARNING: get_renderer() should typically be the last output related call you make before displaying your page&#039;s header.&#039;&#039;&#039; get_renderer() forces the page layout to &#039;base&#039; if it has not already been set and this will almost certainly cause your page to display incorrectly (e.g. no blocks).&lt;br /&gt;
&lt;br /&gt;
Note that as of Moodle 2.9, the render method could be rewritten to use a template. See [[Templates]] for more information.&lt;br /&gt;
&lt;br /&gt;
== Bootstrap renderer ==&lt;br /&gt;
&lt;br /&gt;
Bootstrap renderer is used as a temporary $OUTPUT before the full initialisation of standard core renderer.&lt;br /&gt;
&lt;br /&gt;
== Theme customisations ==&lt;br /&gt;
&lt;br /&gt;
=== Theme renderers ===&lt;br /&gt;
&lt;br /&gt;
Theme renderers are stored in renderers.php file in theme folder (or autoloaded from the classes folder). The actual overriding of renderers is the responsibility of renderer_factory classes which may be selected in theme config.php.&lt;br /&gt;
&lt;br /&gt;
=== Creating a Renderable &amp;quot;widget&amp;quot; in your theme ===&lt;br /&gt;
&lt;br /&gt;
To create a renderable &amp;quot;widget&amp;quot; that could be used in multiple places in your theme (e.g. on the front page, in an overriden renderer for mod_assign etc.)&lt;br /&gt;
Create a renderable and renderer in the following folder:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
/theme/mytheme/output/mywidget/rendererable.php&lt;br /&gt;
theme/mytheme/output/mywidget/renderer.php&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&amp;lt;code php&amp;gt;&lt;br /&gt;
$mywidgetrenderable  = new \theme_mytheme\output\mywidget\renderable($params);&lt;br /&gt;
$mywidgetrenderer = $this-&amp;gt;page-&amp;gt;get_renderer(&#039;theme_mytheme&#039;,&#039;mywidget&#039;); // Or $PAGE-&amp;gt;get_renderer depending on context&lt;br /&gt;
$mywidget = $mywidgetrenderer-&amp;gt;render($mywidgetrenderable);&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
there is a good example of this in moodle core -&amp;gt; /admin/tool/monitor&lt;br /&gt;
&lt;br /&gt;
== Low level HTML output ==&lt;br /&gt;
&lt;br /&gt;
Low level html markup is created via html_renderer class.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
* [[Templates]]&lt;br /&gt;
* [[Theme changes]]&lt;br /&gt;
* Using Moodle [http://moodle.org/mod/forum/discuss.php?d=177535 Totally confused by output renderers...] forum discussion&lt;br /&gt;
&lt;br /&gt;
[[Category:Themes]]&lt;/div&gt;</summary>
		<author><name>Plemaire</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=57099</id>
		<title>Creating a theme based on boost</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Creating_a_theme_based_on_boost&amp;diff=57099"/>
		<updated>2020-03-24T14:12:44Z</updated>

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

		<summary type="html">&lt;p&gt;Plemaire: /* Debugging a web service (WS) error */ link error&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{Moodle Mobile}}== Introduction ==&lt;br /&gt;
&lt;br /&gt;
This guide will help you find and report problems with the Moodle Mobile app on your site.&lt;br /&gt;
&lt;br /&gt;
It is especially useful for the following problems:&lt;br /&gt;
* Unable to log in on your site&lt;br /&gt;
* When you receive one of the following error messages in the app:&lt;br /&gt;
** Can not find data record in database table external_functions&lt;br /&gt;
** Invalid response value detected&lt;br /&gt;
** Cannot get course contents&lt;br /&gt;
&lt;br /&gt;
== Requirements ==&lt;br /&gt;
* Moodle 3.1 onwards (your site needs at least this version)&lt;br /&gt;
* Moodle Desktop app 3.6.1 onwards or Google Chrome/Chromium browser&lt;br /&gt;
[[{{ns:file}}:moodlemobile_enabledebug.png|thumb|300px]]&lt;br /&gt;
&lt;br /&gt;
== Enabling debugging on your Moodle site ==&lt;br /&gt;
&lt;br /&gt;
# Go to Debugging in the Site administration&lt;br /&gt;
# For &amp;quot;Debug messages&amp;quot; select &#039;DEVELOPER&#039;&lt;br /&gt;
# Tick &amp;quot;Display debug messages&amp;quot;&lt;br /&gt;
# Click the &#039;Save changes&#039; button.&lt;br /&gt;
&lt;br /&gt;
Note: Remember to disable debugging again once you have finished debugging your problem.&lt;br /&gt;
&lt;br /&gt;
== Enabling debugging on the mobile app ==&lt;br /&gt;
&lt;br /&gt;
# Go to the More tab&lt;br /&gt;
# Go to Settings &amp;gt; General&lt;br /&gt;
# Enable &amp;quot;Display debug messages&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Note: Remember to disable debugging again once you have finished debugging your problem.&lt;br /&gt;
&lt;br /&gt;
== First try ==&lt;br /&gt;
&lt;br /&gt;
At this point, you may not need fo go further on this guide.&lt;br /&gt;
&lt;br /&gt;
Log-out and log-in again into your site and try to reproduce the error, hopefully, with Moodle and app debugging enabled you will see an explanatory message of what is happening.&lt;br /&gt;
&lt;br /&gt;
If you are unable to find a solution, contact a [https://moodle.com/partners/ Moodle Partner] or post in the [https://moodle.org/mod/forum/view.php?id=7798 Moodle for mobile forum] on moodle.org for non-guaranteed community support.&lt;br /&gt;
&lt;br /&gt;
== Setting up the debugging tool ==&lt;br /&gt;
&lt;br /&gt;
=== Moodle Desktop ===&lt;br /&gt;
&lt;br /&gt;
The recommended way to debug the problem is using the Moodle Desktop app. Please notice that the app version should be 3.6.1 or higher. The desktop app lets you debug some features, such as Single Sign-On, that require a built app to work, rather than a hosted or local ionic build running in a web browser.&lt;br /&gt;
&lt;br /&gt;
You can download the desktop app [https://download.moodle.org/desktop/ from here].&lt;br /&gt;
&lt;br /&gt;
Download the desktop app, install it and open it. Once it&#039;s open, you can open the &amp;quot;Developer tools&amp;quot; with the following shortcut:&lt;br /&gt;
&lt;br /&gt;
* In MacOS: Cmd + Option + I&lt;br /&gt;
* In Windows or Linux: Ctrl + Shift + I&lt;br /&gt;
&lt;br /&gt;
Once the Developer Tools are open, follow these steps:&lt;br /&gt;
&lt;br /&gt;
# Dock the new panels on the right side (in the new panel top-right options choose “Dock to the right” icon)&lt;br /&gt;
# Click the Network tab (at the top-center)&lt;br /&gt;
# Enable the filter (filter shape icon) so it changes to colour red&lt;br /&gt;
# In the new text field displayed when enabling the filter write &amp;lt;code&amp;gt;.php&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now you are ready to debug all the web services requests sent to your Moodle site by the mobile app.&lt;br /&gt;
&lt;br /&gt;
=== Chrome or Chromium ===&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:moodlemobile_chrome_inspect_network.png|thumb|300px]]&lt;br /&gt;
&lt;br /&gt;
Another option is to use Google Chrome or Google Chromium to debug this. If you already have the Moodle Desktop app you can skip this section.&lt;br /&gt;
&lt;br /&gt;
Debugging the mobile app is not so easy, so we have provided an online web version of the app that can be easily debugged using the Chrome browser.&lt;br /&gt;
&lt;br /&gt;
# Open your Chrome browser and go to https://mobileapp.moodledemo.net/&lt;br /&gt;
# Open your browser options (icon at the top-right of your browser window), then go to More tools -&amp;gt; Developer tools&lt;br /&gt;
# Dock the new panels on the right side (in the new panel top-right options choose “Dock to the right” icon)&lt;br /&gt;
# Click the Network tab (at the top-center)&lt;br /&gt;
# Enable the filter (filter shape icon) so it changes to colour red&lt;br /&gt;
# In the new text field displayed when enabling the filter write &amp;lt;code&amp;gt;.php&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Now you are ready to debug all the web services requests sent to your Moodle site by the mobile app.&lt;br /&gt;
&lt;br /&gt;
== Debugging a web service (WS) error ==&lt;br /&gt;
&lt;br /&gt;
[[{{ns:file}}:moodlemobile_chrome_debug_ws_error.png|thumb|300px]]&lt;br /&gt;
&lt;br /&gt;
# Connect to your site and browse to the functionality displaying an error&lt;br /&gt;
# In the right panel you will see a list of requests made by the app to your Moodle site (token.php server.php server.php etc..)&lt;br /&gt;
# Click on each one of them (starting with the last one in the list) but skip those that don’t start with token.php or server.php&lt;br /&gt;
# In the new sub-window open select the “Response” tab and check if you see an error&lt;br /&gt;
# Copy the error then go to the [[:en:Moodle Mobile FAQ|Moodle Mobile FAQ]] in the user docs to check if there is a known solution for it&lt;br /&gt;
# If you are unable to find a solution, contact a [https://moodle.com/partners/ Moodle Partner] or post in the [https://moodle.org/mod/forum/view.php?id=7798 Moodle for mobile forum] on moodle.org for non-guaranteed community support.&lt;br /&gt;
&lt;br /&gt;
== See also ==&lt;br /&gt;
&lt;br /&gt;
* [[Moodle Mobile development using Chrome or Chromium]]&lt;/div&gt;</summary>
		<author><name>Plemaire</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Making_changes_show_up_during_development&amp;diff=55884</id>
		<title>Making changes show up during development</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Making_changes_show_up_during_development&amp;diff=55884"/>
		<updated>2019-04-04T09:56:12Z</updated>

		<summary type="html">&lt;p&gt;Plemaire: /* Capabilities */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Sometime, when you are trying to do Moodle development, you edit the code, and nothing seems to change as a result. This is because, to improve performance, Moodle now has all sorts of caching built in. When this is happening, this page will try to give you the quickest way to make your changes show up in all situation.&lt;br /&gt;
&lt;br /&gt;
== General advice ==&lt;br /&gt;
&lt;br /&gt;
# In your development site, change most of the admin settings like &#039;Cache language strings&#039;, &#039;Cache JavaScript&#039; to be suitable for development. Note that doing this will slow down your development site a bit.&lt;br /&gt;
# If in doubt, visit &amp;lt;nowiki&amp;gt;http://your.domain/moodle&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;/admin&#039;&#039;&#039; to check that the Moodle install is up-to-date.&lt;br /&gt;
# And then &amp;lt;nowiki&amp;gt;http://your.domain/moodle&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;/admin/purgecaches.php&#039;&#039;&#039; and click the &#039;Purge all caches&#039; button. This will slow things down for the next few requests, until the caches have re-populated. Note there is also a CLI tool to purge caches.&lt;br /&gt;
# Depending on what you changed in your plugin, then in addition to the above, you may need to remember to increase the version number in the plugin&#039;s version.php, or the changes will not show up.&lt;br /&gt;
# You may have forgotten to run grunt.&lt;br /&gt;
# If you have just added a new Behat or PHPunit test, you may need to re-run admin/tool/.../cli/init.php&lt;br /&gt;
&lt;br /&gt;
The above steps are a brute force approach. They will probably work, but are probably not the fastest way. Below, we list for all the various type of change you can make, the most efficient way to make the change show up.&lt;br /&gt;
&lt;br /&gt;
== PHP ==&lt;br /&gt;
&lt;br /&gt;
After changing the PHP files (*.php), you should just need to press reload (F5) in your browser.&lt;br /&gt;
&lt;br /&gt;
=== Adding or removing an auto-loaded class ===&lt;br /&gt;
&lt;br /&gt;
If you get class-not-found errors, you need to visit &amp;lt;nowiki&amp;gt;http://your.domain/moodle&amp;lt;/nowiki&amp;gt;&#039;&#039;&#039;/admin&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
== JavaScript ==&lt;br /&gt;
&lt;br /&gt;
After editing the [[Javascript Modules]] source files (amd/src/*.js), if you have Administration -&amp;gt; Appearance -&amp;gt; AJAX and Javascript -&amp;gt; Cache Javascript turned off, then you should just need to reload (F5) in your browser.&lt;br /&gt;
&lt;br /&gt;
If JS caching is on, you need to re-run grunt. (Do you also need to purge a cache??? I don&#039;t think so.)&lt;br /&gt;
&lt;br /&gt;
== CSS ==&lt;br /&gt;
&lt;br /&gt;
After changing the CSS styles (*.css) ...&lt;br /&gt;
&lt;br /&gt;
== SCSS ==&lt;br /&gt;
&lt;br /&gt;
After changing SCSS (*.scss) files ...&lt;br /&gt;
&lt;br /&gt;
== LESS ==&lt;br /&gt;
&lt;br /&gt;
After changing LESS (*.less) files ...&lt;br /&gt;
&lt;br /&gt;
== Language strings ==&lt;br /&gt;
&lt;br /&gt;
After changing language pack strings (lang/en/type_plugin.php):&lt;br /&gt;
&lt;br /&gt;
* The best option is to turn off Admin -&amp;gt; Language -&amp;gt; Language settings -&amp;gt; Cache all language strings when doing development. Then you only need to press F5 to refresh to see your changes.&lt;br /&gt;
* Otherwise you need to Purge all caches (or just the Language strings cache) before reloading.&lt;br /&gt;
&lt;br /&gt;
== Capabilities ==&lt;br /&gt;
&lt;br /&gt;
After changing capabilities (db/access.php) you need to&lt;br /&gt;
&lt;br /&gt;
# Bump the plugin version number.&lt;br /&gt;
# Go to admin -&amp;gt; Notifications.&lt;br /&gt;
&lt;br /&gt;
Then check that the capabilitie shows up on Site administration &amp;gt; Users &amp;gt; Permissions &amp;gt; Define roles for any role.&lt;br /&gt;
&lt;br /&gt;
== Scheduled tasks ==&lt;br /&gt;
&lt;br /&gt;
After changing scheduled tasks (db/tasks.php) you need to&lt;br /&gt;
&lt;br /&gt;
# Bump the plugin version number.&lt;br /&gt;
# Go to admin -&amp;gt; Notifications.&lt;br /&gt;
&lt;br /&gt;
Then check that the task shows up on Admin -&amp;gt; Server -&amp;gt; Scheduled tasks.&lt;br /&gt;
&lt;br /&gt;
== Web services ==&lt;br /&gt;
&lt;br /&gt;
After changing web services (db/services.php) ...&lt;br /&gt;
&lt;br /&gt;
== Database structure ==&lt;br /&gt;
&lt;br /&gt;
After changing the database scheme (db/install.xml, db/upgrade.php) ...&lt;br /&gt;
&lt;br /&gt;
== PHPunit ==&lt;br /&gt;
&lt;br /&gt;
== Behat ==&lt;br /&gt;
&lt;br /&gt;
After you add a new *.feature file, you need to re-run&lt;br /&gt;
&lt;br /&gt;
 $ php admin/tool/behat/cli/init.php&lt;br /&gt;
&lt;br /&gt;
== Mobile support for plugins ==&lt;br /&gt;
&lt;br /&gt;
If you are doing the kind of development described in [[Mobile support for plugins]], using a pre-built version of the app like https://mobileapp.moodledemo.net/.&lt;br /&gt;
&lt;br /&gt;
Note, these steps were originally written by people mostly on question type plugins. Hopefully they are generally applicable, but if they don&#039;t make sense in your case, that might be why. Please edit to improve them.&lt;br /&gt;
&lt;br /&gt;
=== General note ===&lt;br /&gt;
&lt;br /&gt;
If there are lots of red error messages appearing in the JavaScript console (but not the very common error &#039;ERROR Error: Uncaught (in promise): null...&#039; that repeats every minute and fills the console logs!) it is often necessary to clear site data and restart.&lt;br /&gt;
&lt;br /&gt;
# In browser developer tools, go to Application -&amp;gt; Clear storage.&lt;br /&gt;
# Close the browser, and re-launch.&lt;br /&gt;
&lt;br /&gt;
===Adding mobile support to a plugin for the first time===&lt;br /&gt;
&lt;br /&gt;
# Bump the plugin version number.&lt;br /&gt;
# Go to admin -&amp;gt; Notifications.&lt;br /&gt;
# F5 in the app to restart.&lt;br /&gt;
&lt;br /&gt;
=== HTML template ===&lt;br /&gt;
&lt;br /&gt;
After changing an existing template (mobile/*.html), just pull down in the app to refresh.&lt;br /&gt;
&lt;br /&gt;
=== Client-side JavaScript ===&lt;br /&gt;
&lt;br /&gt;
After changing an existing client-side JavaScript (mobile/*.js), press F5 in the browser developer tools to restart the app.&lt;br /&gt;
&lt;br /&gt;
=== Server-side classes/output/mobile.php ===&lt;br /&gt;
&lt;br /&gt;
???&lt;br /&gt;
&lt;br /&gt;
=== Mobile CSS ===&lt;br /&gt;
&lt;br /&gt;
# Bump version number in db/mobile.php&lt;br /&gt;
# Purge caches (specifically the tool_mobile/plugininfo MUC cache)&lt;br /&gt;
# Press F5 to restart the app.&lt;/div&gt;</summary>
		<author><name>Plemaire</name></author>
	</entry>
	<entry>
		<id>https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=55698</id>
		<title>Blocks</title>
		<link rel="alternate" type="text/html" href="https://docs.moodle.org/dev/index.php?title=Blocks&amp;diff=55698"/>
		<updated>2019-03-13T11:52:49Z</updated>

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