Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Creating a theme settings page: Difference between revisions

From MoodleDocs
No edit summary
(85 intermediate revisions by 10 users not shown)
Line 1: Line 1:
<div style="margin:30px;background-color:#FFF102;border:2px solid #A89F00;padding:30px;text-align:center;">Under construction. Please don't make any changes at this point I will remove this notice when I am done --[[User:Sam Hemelryk|Sam Hemelryk]]</div>This document looks at how to create and settings page for your theme and how to make use of those settings both within your CSS and within your layout files.
{{Template:Themes}}
 
This document looks at how to create a settings page for your Moodle theme and how to make use of those settings within the CSS and layout files for your theme.
This is a pretty advanced topic and will require that you have at least an intermediate knowledge of PHP, CSS, and development in general.
 
[[Image:Theme.settings.page.03.png|400px|thumb|Our end goal. The settings page.]]


==Before we begin==
==Before we begin==
There is a huge body of knowledge that we must cover in following through this document and as such I think the best way to write this is as a tutorial for which my intentions are to replicate the standard theme but with a settings page that allows the admin to set background and font colours, set a logo to use with the page, and probably several other minor settings to change the way in which the theme is displayed.
If you want to "code along" with this tutorial - start by [https://github.com/damyon/moodle-theme_photo/releases downloading this theme] and unzipping it to your theme folder.
 
As part of this process I will of course have to create the base of my new theme which will be largely a copy/paste of the current standard theme. I expect that anyone working through this tutorial has previously read the tutorial I wrote on [[Themes 2.0 creating your first theme|creating your first theme]]. If you haven't go read it now because I'm not going to go into much detail until we get to the actual process of customising the theme and introducing the settings page.
 
So before we finally get this started please work check that you can tick of the everything on the following requirements check-list.
* Have a Moodle installation that has already been installed and configured and is ready to use
* Have full read/write access to that installation.
* Be prepared to delete that installation at the end of this... we will destroy it!
* Have a development environment prepared and ready to use. This includes:
** Your favourite editor installed, running, and pointed at the themes directory of your installation.
** You browser open and your site visible.
** A bottomless coffee pot... decaf won't help you with this one.
* Have turned on theme designer mode, if you don't know what this is please read the [[Themes 2.0 creating your first theme|creating your first theme]] tutorial.
* Have turned on allowthemechangeonurl. This setting allows you to change themes on the URL and is very handy when developing themes.
* And finally an insane ambition to create a customisable theme.
 
==Our goals for this tutorial==
The following is just a list goals that I hope to achieve during this tutorial. They are laid out here so that I can easily refer back to them and so that you can easily find them.
# Create a new theme called '''demystified''' based on the standard theme within Moodle 2.0 but defines it own layout files.
# Make some minor changes to that theme to allow us to more easily see what is going on.
# Create a settings page for the demystified theme
# Add several settings to our settings page
# Use some of those settings to alter our CSS
# Use the rest of those settings within our layout file.
# Discuss the good, the bad, and limits of what we have just created.
 
So I can see you are all very excited about this point and that you would love to know what settings we are going to create; So here they are:


A setting to ...
This is a working example of a theme with some settings extending "Boost". You will need to be using Moodle 3.2 as the Boost theme is only available for this version of Moodle. The information in this tutorial is still valid for versions before 3.2.
* change the background colour (CSS).
* set the path to an image that we will use as a logo on all pages (Layout files).
* override the width of the block regions (CSS).
* allow a note to be added to the footer of all pages (Layout files).
* allow custom CSS to be written to do anything the user wants.


==Creating the demystified theme==
We will add some more settings to this theme and explain how to use the settings in the layout files and in the SCSS for this theme.  
Before we start here I want to remind you that I am going to look at this only briefly as I am making the assumption that you have read the [[Themes 2.0 creating your first theme|creating your first theme]] tutorial.


Well lets get into it....


The first thing we need to do is create a directory for our theme which we will call demystified.  
== settings.php ==
Themes define their settings and add them to the administration pages in their "settings.php". The code that builds all of the admin settings looks for this file in every installed plugin (not just themes).


So within your Moodle directory create the following folder '''moodle/theme/demystified'''. At the same time you can also create the following files and folders which we will get to soon.
In the example theme we can see a settings.php file created already - lets see what it's doing.
* The file '''moodle/theme/demystified/config.php''' for our config information.
* The directory '''moodle/theme/demystified/layout''' for our layout files.
* The directory '''moodle/theme/demystified/style''' for our css files.
* The file '''moodle/theme/demystified/style/core.css''' which will contain our special CSS.


Next we will copy the layout files from the base theme to our new theme demystified. We are basing our theme on the base theme however because we want to make changes to our layout files we will need to create out own. In this case coping them from the base them is fine... so copy all of the layout files from '''moodle/theme/base/layout''' to '''moodle/theme/demystified/layout'''.
There should be three files that you just copied:
# embedded.php
# frontpage.php
# general.php
Now we need to populate demystified/config.php with the settings for our new theme. They are as follows:
<code php>
<code php>
$THEME->name = 'demystified';
// This line protects the file from being accessed by a URL directly.                                                             
defined('MOODLE_INTERNAL') || die();          
</code>
</code>
Simply sets the name of our theme.


<code php>
We put this in all php files that are not meant to be accessed directly. It prevents someone from typing the url to one of these files and accidentally running some code or seeing a strange error.
$THEME->parents = array('standard','base');
</code>
This theme is extending both the standard theme and the base theme. Remember when extending a theme you also need to extend its parents or things might not work correctly.


<code php>
<code php>
$THEME->sheets = array('core');
// This is used for performance, we don't need to know about these settings on every page in Moodle, only when                     
// we are looking at the admin settings pages.                                                                                     
if ($ADMIN->fulltree) {
</code>
</code>
This tells our theme that we want to use the file '''demystified/style/core.css''' with this theme.


<div style="height:300px;overflow-y:scroll;">
As the comment says, we don't need to build the whole list of settings on every single page in Moodle - only when we are actually browsing through the admin settings pages. So we don't create these settings unless they are needed on this page.
<code php>
$THEME->layouts = array(
    // Most backwards compatible layout without the blocks - this is the layout used by default
    'base' => array(
        'file' => 'general.php',
        'regions' => array(),
    ),
    // Standard layout with blocks, this is recommended for most pages with general information
    'standard' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // Main course page
    'course' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
        'options' => array('langmenu'=>true),
    ),
    'coursecategory' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // part of course, typical for modules - default page layout if $cm specified in require_login()
    'incourse' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // The site home page.
    'frontpage' => array(
        'file' => 'frontpage.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // Server administration scripts.
    'admin' => array(
        'file' => 'general.php',
        'regions' => array('side-pre'),
        'defaultregion' => 'side-pre',
    ),
    // My dashboard page
    'mydashboard' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
        'options' => array('langmenu'=>true),
    ),
    // My public page
    'mypublic' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    'login' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('langmenu'=>true),
    ),


    // Pages that appear in pop-up windows - no navigation, no blocks, no header.
    'popup' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
    ),
    // No blocks and minimal footer - used for legacy frame layouts only!
    'frametop' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('nofooter'=>true),
    ),
    // Embeded pages, like iframe/object embeded in moodleform - it needs as much space as possible
    'embedded' => array(
        'file' => 'embedded.php',
        'regions' => array(),
        'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
    ),
    // Used during upgrade and install, and for the 'This site is undergoing maintenance' message.
    // This must not have any blocks, and it is good idea if it does not have links to
    // other places - for example there should not be a home link in the footer...
    'maintenance' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
    ),
);
</code>
</div>
Now that all looks very complicated however its really not too bad as it is just copied from the base theme's config.php file. We can do this because we copied the layout files from the base theme to begin with and for the time being there are no changes that we wish to make. Simply open up '''theme/base/config.php''' and copy the layouts from there.
And that is it. The config.php file for our demystified theme is complete. The full source is shown below:
<div style="height:300px;overflow-y:scroll;">
<code php>
<code php>
<?php


// This file is part of Moodle - http://moodle.org/
    // Boost provides a nice setting page which splits settings onto separate tabs. We want to use it here.                        
//
     $settings = new theme_boost_admin_settingspage_tabs('themesettingphoto', get_string('configtitle', 'theme_photo'));
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
/**
* The demystified theme config file
*
* This theme was created to document the process of adding a settings page to a theme
*
* @copyright 2010 Sam Hemelryk
* @license  http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
 
// The name of our theme
$THEME->name = 'demystified';
 
// The other themes this theme extends
$THEME->parents = array('standard','base');
 
// The CSS files this theme uses (located in the style directory)
$THEME->sheets = array('core');
 
// The layout definitions for this theme
$THEME->layouts = array(
    // Most backwards compatible layout without the blocks - this is the layout used by default
    'base' => array(
        'file' => 'general.php',
        'regions' => array(),
    ),
    // Standard layout with blocks, this is recommended for most pages with general information
    'standard' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // Main course page
    'course' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
        'options' => array('langmenu'=>true),
    ),
     'coursecategory' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // part of course, typical for modules - default page layout if $cm specified in require_login()
    'incourse' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // The site home page.
    'frontpage' => array(
        'file' => 'frontpage.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    // Server administration scripts.
    'admin' => array(
        'file' => 'general.php',
        'regions' => array('side-pre'),
        'defaultregion' => 'side-pre',
    ),
    // My dashboard page
    'mydashboard' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
        'options' => array('langmenu'=>true),
    ),
    // My public page
    'mypublic' => array(
        'file' => 'general.php',
        'regions' => array('side-pre', 'side-post'),
        'defaultregion' => 'side-post',
    ),
    'login' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('langmenu'=>true),
    ),
 
    // Pages that appear in pop-up windows - no navigation, no blocks, no header.
    'popup' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
    ),
    // No blocks and minimal footer - used for legacy frame layouts only!
    'frametop' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('nofooter'=>true),
    ),
    // Embeded pages, like iframe/object embeded in moodleform - it needs as much space as possible
    'embedded' => array(
        'file' => 'embedded.php',
        'regions' => array(),
        'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
    ),
    // Used during upgrade and install, and for the 'This site is undergoing maintenance' message.
    // This must not have any blocks, and it is good idea if it does not have links to
    // other places - for example there should not be a home link in the footer...
    'maintenance' => array(
        'file' => 'general.php',
        'regions' => array(),
        'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true),
    ),
);
</code>
</code>
</div>
The screenshot below shows the both the directory structure we have now created and a screenshot of the theme presently.
[[Image:Theme.settings.page.01.png]]
To view the theme so far open you browser and enter the URL of your site followed by '?theme=demystified'. You should see the theme that we just created which will look exactly like the base standard theme.
The final thing that we want to do is add a little bit of CSS to the demystified theme that will both visually set this theme apart from the standard theme and second build a the base on which our settings can later build.
I added the following snippet of CSS to the file '''demystified/style/core.css'''.
<code css>
html {background-color:#DDD;}
body {margin:30px;padding:0;border:1px solid #333;border-width:0 10px 0 10px;background-color:#333;}
body #page {background-color:#FFF;position:relative;top:-10px;}
.block .header {background-image:none;background-color:#0C5CAC;border:1px solid #0C5CAC;color:#FFF;}
.block {border-color:#4BA7FF;background-color:#DDEEFF;}
.block .content {background-color:#F1F8FF;}
a:link,
a:visited {color:#0C5CAC;}
a:hover {color:#C77500;}
#page #page-header {background-color:#0C5CAC;margin:0;padding:0;width:100%;color:#fff;}
#page #page-header a:link, #page #page-header a:visited {color:#FFAC02}
#page #page-header .navbar, #page #page-header .navbar a:link, #page #page-header .navbar a:visited {color:#0C5CAC;}
</code>
The CSS that we have just added to our theme sets a couple of colours on the front page. Presently this is the only CSS I will add, I know it isn't complete by any means but it achieves it's purpose as the screenshot below illustrates.
[[Image:Theme.settings.page.02.png]]
And with that I will move on to the real purpose of this tutorial, creating the settings page
==Setting up the settings page==
With the demystified theme set up in its early stage it is time to create the settings page. This is where the real PHP fun begins.
For those of you who happen to be familiar with development of modules, blocks or other plugin types you have probably encountered settings pages before and this is not going to be any different.
However for those who haven't which I imagine is most of you this is going to be quite a challenge. I will try to walk through this step by step however if at any point you get stuck don't hesitate to ask in the forums as I imagine you will get a speedy response.
===How settings pages work in Moodle===
Settings pages can be used by nearly every plugin type of which themes is of course one. The way in which it all works isn't too tricky to understand.
All of the settings for Moodle can be configured through the admin interfaces when logged in. I am sure that everyone here has seen those admin pages and has changed a setting or two before so you will all know what I am talking about. Well the settings page for theme is no different. It will be shown in the admin pages tree under '''Appearance > Themes''' and all we have to do is tell Moodle what settings there are.
This is done by creating a settings.php file within out theme into which we will add code that tells Moodle about the settings we want to add/use.
When telling Moodle about each setting we are simply creating a new admin_setting instance of the type we want and the properties we want and then adding it to our settings page.
There is really not much more too it at this level. Things can get very complex very fast so the best thing we can do now is start creating our settings.php file for the demystified theme and see where it leads us.
===Creating the settings page===
So as mentioned before we need a settings.php file which we will create now. To begin with create the file '''theme/demystified/settings.php''' and open it in your favourite editor so its ready to go.


Before we start adding code lets just remember the settings that we want to create:
In order to create any settings in our theme, we need to create the setting, and we need to add it to a settings page.
* change the background colour (CSS).
* set the path to an image that we will use as a logo on all pages (Layout files).
* override the width of the block regions (CSS).
* allow a note to be added to the footer of all pages (Layout files).
* allow custom CSS to be written to do anything the user wants.


Alright.
Normally before including the settings.php file for a plugin Moodle will create a variable named $settings which is an instance of the "admin_settingspage" class. In the plugin, settings can be added to the page by using $settings->add(). In this theme we do something special though - we replace the default $settings variable with a new one which has new functionality (tabs).  


Now thinking about this the first setting is as basic as it gets, all we need is a text box that the user can type an image into.
This theme_boost_admin_settingspage_tabs class is defined in the boost theme (theme/boost/classes/admin_settingspage_tabs.php) and we can use it in boost or any theme that inherits from boost. It will probably be moved in to core so it can be used by any theme very soon because it is very useful.


The second is to allow a logo to be used in the header of each page. What we want here is a path but should it be a physical path e.g. C:/path/to/image.png or should it be a web path e.g. http://mysite.com/path/to/image.png?
So $settings is our settings page that we can add things to.  
For the purpose of this tutorial I am going to go with a web path because it is going to be easier to code and will hopefully be a little easier to understand to begin with.
 
The third settings is very straight forward, we will just have a plain text box into which a width can be typed that will be used to determine the width of the block regions.
 
The forth and the fifth settings are also pretty straight forward, they we use a textarea into which the user can enter what ever they want and we will do something useful with it.
 
Now that we have an understanding about the settings we wish to define pull up your editor and lets start coding....


<code php>
<code php>
<?php
/**
* Settings for the demystified theme
*/


$temp = new admin_settingpage('theme_demystified', get_string('configtitle','theme_demystified'));
    // Each page is a tab - the first is the "General" tab.                                                                       
    $page = new admin_settingpage('theme_photo_general', get_string('generalsettings', 'theme_photo'));    
    ...
    // Create some settings and add them to $page with $page->add().
    ...
    // Must add the page after defining all the settings!                                                                         
    $settings->add($page); 
</code>
</code>
This is the first bit of code we must enter, the first line is of course just the opening php tag, secondly we have a comment that describes this file, and then we get create a new '''admin_settingspage object'''.


This admin_settingspage object that we have just created is a representation of our settings page and is the what we add our new settings to. When creating it we give it two arguments, first the name of the page which is in this case '''theme_''themename''''' and the title for the page which we get with the get_string method.
To create each tab in this theme_boost_admin_settingspage_tabs class - we create a new settings pages, add all the settings to them and then add each one with $settings->add(). Each page will display as a separate tab.


At the moment I'm not going to worry about adding the string, we will get to that latter once we have defined all of our settings.
If we were not using tabs we could just create each setting and add it to the page with $settings->add().


====Background colour====
To create a setting we create a subclass of the admin_setting class. These settings are all defined in lib/adminlib.php so you can search and find the right kind of setting.


With the page now created as ''$temp'' lets add our first setting: Background colour.
The constructors for each of the settings classes tend to use similar arguments (but check the docs for each one to be sure).


Example:
<code php>
<code php>
// Background colour setting
$name = 'theme_demystified/backgroundcolor';
$title = get_string('backgroundcolor','theme_demystified');
$description = get_string('backgroundcolordesc', 'theme_demystified');
$default = '#DDD';
$setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_CLEAN, 12);
$temp->add($setting);
</code>
Thankfully this isn't as difficult as it probably initially looks.


The first line of code is creating a variable for the name of the background colour setting. In this case it is '''theme_demystified/backgroundcolor'''.
    $setting = new admin_setting_configtext('theme_photo/textsetting', get_string('textsetting','theme_photo'), get_string('textsetting_desc', 'theme_photo'), 'defaultvalue', PARAM_NOTAGS, 50);                                                             
 
    // Any setting that should cause the CSS to be recompiled should have this callback.
The name is very important, for the setting to be usable we have to follow a strict naming convention. '''theme_''themename''/''settingname''''' where '''''themename''''' is the name of the theme the setting is for and '''''settingname''''' is the name for the setting by which we will also use it.
    $setting->set_updatedcallback('theme_reset_all_caches');                                                   
 
    // We are using tabs, so add this to page. If we were not using tabs this would be $settings->add($setting);
The second line of code creates a variable that contains the title of the setting. This is what the user sees to the right of the setting on the settings page and should be a short description of the setting. Here we are again using the get_string method so we will need to remember to add that string later on.
    $page->add($setting);
 
The third line of code sets the description. This should describe what the setting does or how it works and again we will use the get_string method.
 
The fourth line creates a variable that will be used as the default value for the setting. Because this setting is a colour we want an HTML colour to be the default value.
 
The fifth line is where we put it all together. Here we create a new '''admin_setting_configtext''' object. This object will represent the background colour setting.
 
When we create it we need to give it 6 different things.
# The name of the setting. In this case we have a variable '''$name'''.
# The title for this setting. We used the variable '''$title'''.
# The description of the setting '''$description'''.
# The default value for the setting. '''$default''' is the variable this.
# The type of value we want the user to enter. For this we have used PARAM_CLEAN which tells Moodle to get rid of any nasties from what the user enters.
# The size of the field. In our case 12 characters will be plenty.
 
The sixth and final line of code adds our newly created setting to the admin page we created earlier.
 
That is it we have successfully created and added our first setting, however there are several more to settings to do, and three are a couple of important things that you need to be aware of before we move on.
 
First: There are several different types of settings that you can create and add to a page and each one may differ in what they need you to give them. In this case it was name, title, description, default, type, and size. However other settings will likely require different things. Smart editors like Netbeans or Eclipse can tell you what is required, otherwise you will need to research it.
 
Second: Normally settings are declared on one line as follows:
<code php>
$temp->add(new admin_setting_configtext('theme_demystified/backgroundcolor', get_string('backgroundcolor','theme_demystified'), get_string('backgroundcolordesc', 'theme_demystified'), '#DDD', PARAM_CLEAN, 12));
</code>
</code>
While this is structurally identical as all we have done is move everything onto one line and do away with the variables it is a little harder to read when you are learning all of this.


====The logo file====
The first 4 arguments for all these settings are always the same - the last ones are specific to the type of setting. Explaining each one in order.
Time to create the second setting that will allow the user to enter a URL to an image they wish to use as the logo on their site.
* theme_photo/textsetting - This is the name of the setting. It starts with the component name for the plugin - then / - then the unique name of the setting in this plugin.
<code php>
* get_string('textsetting', 'theme_photo') - This is the name of the setting that will be displayed to the admin. We use a lang string so it can be translated.
// Logo file setting
* get_string('textsetting_desc', 'theme_photo') - This is the description of the setting that will be displayed to the admin. We use a lang string so it can be translated. We name this string the same as the name of the setting with _desc at the end. This is recommended so the related strings show up together in the translation website.
$name = 'theme_demystified/logo';
* defaultvalue - This is the default value of the setting and the install / upgrade for your plugin will set this value in the database automatically.  
$title = get_string('logo','theme_demystified');
$description = get_string('logodesc', 'theme_demystified');
$setting = new admin_setting_configtext($name, $title, $description, '', PARAM_URL);
$temp->add($setting);
</code>
The first thing that you will notice about this setting that it is very similar to the first setting to set the background colour, infact all we have changed is the name, title, description, and default value. We have however changed the value type from PARAM_CLEAN to PARAM_URL, this makes sure the user enters a URL. You will also notice that for this one we don't set a size for the field as we have no idea how long the URL will be.


====Block region width====
The rest of the arguments are specific to the admin_setting_configtext class. They are:
The third setting should allow the user to set set a width for the block regions that will be used as columns. (We could have called it column width I suppose)
* PARAM_NOTAGS - This is the type of text that should be validated in this setting. It can be any of the PARAM values defined in lib/moodlelib.php.
* 50 - This is the size of the field. Things like URLs should have a longer setting so all of the text will be visible.


For this setting I want to do something a little different from the previous two, here I want to use a select box so that the user selects a width for the column from a list I provide.
How does my setting get saved? It is stored in the mdl_config_plugins table as text and can be retrieved in any php code with:
<code php>
<code php>
// Block region width
$name = 'theme_demystified/regionwidth';
$title = get_string('regionwidth','theme_demystified');
$description = get_string('regionwidthdesc', 'theme_demystified');
$default = 200;
$choices = array(150=>'150px', 170=>'170px', 200=>'200px', 240=>'240px', 290=>'290px', 350=>'350px', 420=>'420px');
$setting = new admin_setting_configselect($name, $title, $description, $default, $choices);
$temp->add($setting);
</code>
So looking at the code: The four three lines you will recognise. $name, $title, $description, and $default are all being set.
The fifth line of code however introduces something new. Of course in order to have a select box we have to have options, in this case we have an array of options stored in the variable $choices.
The lines after should look familiar again, the only difference being that instead of a admin_setting_configtext setting we have created a admin_setting_configselect for which we must give the choice for the select box as the fifth argument.
Woohoo, we've just created our first select box setting.
====Foot note====
Now to create the foot note setting. Here we want the user to be able to enter some arbitrary text that will be used in the footer of the page. For this I want the user to be able to enter some HTML so I will create an editor setting.
<code php>
// Foot note setting
$name = 'theme_demystified/footnote';
$title = get_string('footnote','theme_demystified');
$description = get_string('footnotedesc', 'theme_demystified');
$setting = new admin_setting_confightmleditor($name, $title, $description, '');
$temp->add($setting);
</code>
How simple is that!
It is just about identical to the first two settings except that for this we have created a admin_setting_confightmleditor setting rather than a text setting.
Note: You can also set the columns and rows for the editor setting using the fifth and sixth arguments.


====Custom CSS====
  $value = get_config('theme_photo', 'textsetting');
The final setting is to allow the user to add some custom CSS to the theme that will be used on every page. I want this to be a plain textarea into which the user can enter CSS.
<code php>
// Custom CSS file
$name = 'theme_demystified/customcss';
$title = get_string('customcss','theme_demystified');
$description = get_string('customcssdesc', 'theme_demystified');
$setting = new admin_setting_configtextarea($name, $title, $description, '');
$temp->add($setting);
</code>
</code>
Just like the editor or text settings. It's getting very easy now!


====Finishing settings.php====
What kinds of settings exist?
With all of our settings defined and added to our page that we created right at the beginning it is time to finish it all off.
<code php>
// Add our page to the structure of the admin tree
$ADMIN->add('themes', $temp);
</code>
The above line of code is the final line for the page. It is adding the page that we have created '''$temp''' to the admin tree structure. In this case it is adding it to the themes branch.


The following is the completed source for our settings.php ..... for your copy/paste pleasure.
There are heaps - some of the most useful are listed here:
<div style='height:300px;overflow:auto;'>
<code php>
<?php


/**
* admin_setting_configtext - The most flexible setting, the user enters text.
* Settings for the demystified theme
* admin_setting_configtextarea - General text area without html editor.  Useful for things like raw CSS
*/
* admin_setting_confightmleditor - A full html editor using the systems default text editor. Good for editing HTML
* admin_setting_configpasswordunmask - Works like a password field - but isn't one. Good for shared secrets etc
* admin_setting_configfile - Good for listing a file stored on the server. Does not allow uploading files
* admin_setting_configexecutable - More specific version of admin_setting_configfile. The file is checked to make sure it can be executed by the webserver
* admin_setting_configcheckbox - Are you cool [ ]
* admin_setting_configselect - Choose from a list of values
* admin_setting_configstoredfile - Allow uploading of files and storing in moodle file storage
* admin_setting_configcolourpicker - Interactive colour picker


// Create our admin page
== Add a setting and use it in SCSS (or less or css) ==
$temp = new admin_settingpage('theme_demystified', get_string('configtitle','theme_demystified'));


// Background colour setting
Lets add a new setting and show how to use the value of the setting in our SCSS, less or css.
$name = 'theme_demystified/backgroundcolor';
$title = get_string('backgroundcolor','theme_demystified');
First - we will add a new colour setting to our settings page.
$description = get_string('backgroundcolordesc', 'theme_demystified');
$default = '#DDD';
$setting = new admin_setting_configtext($name, $title, $description, $default, PARAM_CLEAN, 12);
$temp->add($setting);


// Logo file setting
''theme/photo/settings.php''
$name = 'theme_demystified/logo';
$title = get_string('logo','theme_demystified');
$description = get_string('logodesc', 'theme_demystified');
$setting = new admin_setting_configtext($name, $title, $description, '', PARAM_URL);
$temp->add($setting);
 
// Block region width
$name = 'theme_demystified/regionwidth';
$title = get_string('regionwidth','theme_demystified');
$description = get_string('regionwidthdesc', 'theme_demystified');
$default = 200;
$choices = array(150, 170, 200, 240, 290, 350, 420);
$setting = new admin_setting_configselect($name, $title, $description, $default, $choices);
$temp->add($setting);
 
// Foot note setting
$name = 'theme_demystified/footnote';
$title = get_string('footnote','theme_demystified');
$description = get_string('footnotedesc', 'theme_demystified');
$setting = new admin_setting_confightmleditor($name, $title, $description, '');
$temp->add($setting);
 
// Custom CSS file
$name = 'theme_demystified/customcss';
$title = get_string('customcss','theme_demystified');
$description = get_string('customcssdesc', 'theme_demystified');
$setting = new admin_setting_configtextarea($name, $title, $description, '');
$temp->add($setting);
 
// Add our page to the structure of the admin tree
$ADMIN->add('themes', $temp);
</code>
</div>
 
===Creating a language file and adding our strings===
As I'm sure none of your have forgotten throughout the creation of the our settings.php page we used alot of strings that I mentioned we would set later on. Well not it is time to set those strings.
 
First up create the following directory and file for our language strings:
* Directory '''theme/demystified/lang'''
* Directory '''theme/demystified/lang/en'''
* File '''theme/demystified/lang/theme_demystified.php'''
 
What we have created here is the required structure for Moodle to start looking for language strings.
 
First up Moodle searches locates the lang directory, once found it looks within a that directory for a directory that makes the character code for the language the user has selected, by default this is '''en''' for English, once that is found it looks for the appropriate language file in this case theme_demystified from which it will load all language strings for our theme.
 
If English isn't your first language simply replace the en directory with one that uses your chosen languages character code (two letters).
 
We can now add our language strings to '''theme/demystified/lang/theme_demystified.php'''. Copy and paste the following lines of PHP into this file.
<code php>
<code php>
<?php


/**
    $name = 'theme_photo/cardbg';                                                                                                  
* This file contains the strings used by the demystified theme
    $title = get_string('cardbg', 'theme_photo');                                                                                  
*/
    $desc = get_string('cardbg_desc', 'theme_photo');                                                                              
 
    $setting = new admin_setting_configcolourpicker($name, $title, $desc, '#ffffff');  
$string['backgroundcolor'] = 'Background colour';
    $setting->set_updatedcallback('theme_reset_all_caches');                                                  
$string['backgroundcolordesc'] = 'This sets the background colour for the theme.';
    $page->add($setting);
$string['configtitle'] = 'Demystified theme';
$string['customcss'] = 'Custom CSS';
$string['customcssdesc'] = 'Any CSS you enter here will be added to every page allowing your to easily customise this theme.';
$string['footnote'] = 'Footnote';
$string['footnotedesc'] = 'The content from this textarea will be displayed in the footer of every page.';
$string['logo'] = 'Logo';
$string['logodesc'] = 'Enter the URL to an image to use as the logo for this site. Should be http://www.yoursite.com/path/to/logo.png';
$string['regionwidth'] = 'Column width';
$string['regionwidthdesc'] = 'This sets the width of the two block regions that form the left and right columns.';
</code>
</code>


In the above lines of code I have added an entry for each language string we used in the settings.php file. When adding language strings like this make sure you use single quotes and try to keep things alphabetical - it helps greatly when managing strings.
Copy this new setting into the settings.php for theme_photo.


Now when we view the settings page there will not be any errors or strings missing.
''theme/photo/lang/en/theme_photo.php''
 
===Having a look at what we have created===
Now that we have created our settings page (settings.php) and added all of the language strings it is time to have a look at things within your browser.
 
Open your browser and enter the URL to your installation. When you arrive your site login as an admin.
 
If you are not redirected to view new settings change your URL to http://www.yoursite.com/admin/ and your will see a screen to set the new theme settings we have just created. This lets us know that everything has worked correctly.
 
At any point now you are able to log in as admin and within the settings block browse to '''Site administration > Appearance > Themes > Demystified theme''' to change those settings.
 
The screenshot below shows you what you should see at this point:
 
[[Image:Theme.settings.page.03.png|715px|thumb|left|The settings page we just created]]
 
==Using the settings in CSS==
With the settings page now created and operational it is time to make use of our new settings. The settings that we want to use within our CSS is as follows:
 
; backgroundcolor : Will be used to set the background colour in CSS.
; regionwidth : Will be the width of the column for CSS.
; customcss : Will be some custom CSS to add to our stylesheet.
 
At this point those names are the names we used for our setting with the slash and everything before it having been removed.
 
Before we start tearing into some code it is important that we have a look at what we are going to do and how we are going to go about it.
 
===How it all works within Moodle===
The first thing to understand is that while Moodle allows you to create a settings page and automates it inclusion and management right into the admin interfaces there is no smart equivalent for using the settings. This is simply because there is no way to predict how people will want to use the settings.
 
However don't think of this as a disadvantage, in fact it is quite the contrary. Although we can't just ''use'' our settings we can take full control over how and where we use them. It means it will take a little more code but in the end that will work to our advantage as we can do anything we want.
 
Moodle does help us out a little but not in an obvious way. The first thing that Moodle does is look for a config variable '''csspostprocess''' that should be the name of a function which we want called to make any changes to the CSS after it has been prepared.
 
The second thing Moodle does is include a lib.php from the theme's directory if one exists (also for the themes the current theme extends.) which ensures that as long as we write our code within ''theme/demystified/lib.php'' it will be included and ready to be used.
 
The third and final thing Moodle does that will help us out here is ensure that by the time any of code is ready to execute the settings have been prepared and are ready to be used within a theme config object which is passed into our csspostprocess function.
 
===Our plan===
As you have already probably guessed we will need to create a function to make the changes to the CSS that we want. We will then set the theme config option '''$THEME->csspostprocess''' to the name of our function.
 
By doing this when Moodle builds the CSS file it will call our function afterwards with the CSS and the theme object that contains our setting.
 
Now we know that we will use the csspostprocess function but how are we going to change the CSS, we could get the function to add CSS, or we could get the function to replace something within the CSS. My personal preference is to replace something within the CSS, just like what is happening with images. If you want to use an image within CSS you would write <nowiki>[[pix:theme|imagename]]</nowiki>.
 
For settings I am going to use <nowiki>[[setting:settingname]]</nowiki>, this way it looks a bit like something you are already familiar with.
 
What we need to decide upon next is the best way in which to replace our settings tag with the settings that the user has set.
 
Here I two immediate options available to us:
# Make the csspostprocess function do all the work.
# Make the csspostprocess function call a separate function for each setting.
Solution 1 might sound like the simplest however it is going to result in a '''VERY''' complex function. Remember the user might have left settings blank or entered something that wouldn't be valid so we would need to make the sure there is some validation and a good default.
Because of this I think that solution 2 is the better solution.
 
So we are going to need a css post process method and a function for each of the three settings we have that will do the replacements.
<code php>
<code php>
// This is our css post process function
$string['cardbg'] = 'Content background';                                                                                         
function demystified_process_css($css, $theme) {};
$string['cardbg_desc'] = 'A setting to control the background colour for content.';  
// This replaces [[setting:backgroundcolor]] with the background colour
function demystified_set_backgroundcolor($css, $backgroundcolor) {};
// This replaces [[setting:regionwidth]] with the correct region width
function demystified_set_regionwidth() {$css, $regionwidth};
// This replaces [[setting:customcss]] with the custom css
function demystified_set_customcss() {$css, $customcss};
</code>
</code>


What you should note about the above functions is that they all start with the theme's name. This is required to ensure that the functions are named uniquely as it is VERY unlikely that someone has already created these functions.
Add the lang strings to the language file for the theme.


So with our plan set our lets start writing the code.
Now clear your caches and you should see the new setting show up on the settings page for this theme (which ever tab you added it to).


===Writing the code===
This is good - we can change the setting and the value is saved - but it doesn't do anything yet.
The very first thing that we need to do is create a lib.php for our theme into which our css processing functions are going to go. So please at this point create '''theme/demystified/lib.php''' and open it in your editor ready to go.


The first bit of code we have to write is the function that the function that will be called by Moodle to do the processing '''demystified_process_css'''. Before we start out please remember that the wonderful thing about coding is that there is any number of solutions to a problem. The solutions that you are seeing here in this tutorial are solutions that I have come up with to meet fulfil the needs of the tutorial without being so complex that they are hard to understand.
In this case we want to use this new setting to set the value of a bootstrap variable.


====The function: demystified_process_css====
In theme_photo we do not define any value for the $THEME->prescsscallback which means it will be using the callback from the parent theme which is "theme_boost_get_pre_scss". If we look in the lib.php file from boost too see what this callback is doing we will see it is getting the value of the 'brandcolor' setting and using it to set a SCSS variable named 'brand-primary'. In our theme we want to do the same thing, but for the 'cardbg' setting as well.


''theme/photo/config.php''
<code php>
<code php>
function demystified_process_css($css, $theme) {
$THEME->prescsscallback = 'theme_photo_get_pre_scss';
 
    if (!empty($theme->settings->backgroundcolor)) {
        $backgroundcolor = $theme->settings->backgroundcolor;
    } else {
        $backgroundcolor = null;
    }
    $css = demystified_set_backgroundcolor($css, $backgroundcolor);
 
    if (!empty($theme->settings->regionwidth)) {
        $regionwidth = $theme->settings->regionwidth;
    } else {
        $regionwidth = null;
    }
    $css = demystified_set_regionwidth($css, $regionwidth);
 
    if (!empty($theme->settings->customcss)) {
        $customcss = $theme->settings->customcss;
    } else {
        $customcss = null;
    }
    $css = demystified_set_customcss($css, $customcss);
 
    return $css;
}
</code>
</code>


So lets look at the things that make up this function:
''theme/photo/lib.php''
 
<code php>
<code php>
function demystified_process_css($css, $theme) {
function theme_photo_get_pre_scss($theme) {                                                                                        
     //.....
    global $CFG;                                                                                                                   
     return $css
                                                                                                                                   
}
    $scss = '';                                                                                                                   
    $configurable = [                                                                                                             
        // Config key => [variableName, ...].                                                                                     
        'brandcolor' => ['brand-primary'],                                                                                         
        'cardbg' => ['card-bg'],                                                                                                   
    ];                                                                                                                             
                                                                                                                                   
     // Prepend variables first.                                                                                                   
    foreach ($configurable as $configkey => $targets) {                                                                           
        $value = isset($theme->settings->{$configkey}) ? $theme->settings->{$configkey} : null;                                   
        if (empty($value)) {                                                                                                       
            continue;                                                                                                             
        }                                                                                                                         
        array_map(function($target) use (&$scss, $value) {                                                                         
            $scss .= '$' . $target . ': ' . $value . ";\n";                                                                       
        }, (array) $targets);                                                                                                     
    }                                                                                                                             
                                                                                                                                   
    // Prepend pre-scss.                                                                                                           
    if (!empty($theme->settings->scsspre)) {                                                                                       
        $scss .= $theme->settings->scsspre;                                                                                       
    }                                                                                                                             
                                                                                                                                   
     return $scss;                                                                                                                 
}          
</code>
</code>


This of course is the function declaration.
This is a good way to create SCSS variables for use in your theme. Variables work well in SCSS because they can be defined as
 
<code scss>
The function gets given two variables, the first $css is a pile of CSS as one big string, and the second is the theme object that contains all of the configuration, options, and settings for our theme.
$myvariable: #FF0 !default;
 
It then returns the $css variable, essentially returning the modified CSS.
 
<code php>
    //...
    if (!empty($theme->settings->backgroundcolor)) {
        $backgroundcolor = $theme->settings->backgroundcolor;
    } else {
        $backgroundcolor = null;
    }
    $css = demystified_set_backgroundcolor($css, $backgroundcolor);
    //...
</code>
 
Here we are processing our first setting ''backgroundcolor''. The first thing that we need to do is check whether it has been set and whether it has a value. If it has then we store that value in '''$backgroundcolor'''. It is doesn't have a value then we set $backgroundcolor to null. This ensures that $backgroundcolor is set because if it isn't then you are going to get a notice (if you have debugging on).
 
The final line of this block calls the function '''demystified_set_backgroundcolor'''. We haven't written this function yet but we will shortly. When we call it we give it the $css variable that contains all of the CSS and we give it the background color variable $background. Once this function is finished it returns the $css variable with all of the changes made much like how our css processing function works.
 
What you should also note about this code is this:
<code php>
$theme->settings->backgroundcolor
</code>
As mentioned earlier $theme is an object that contains all of the configuration and settings for our theme. The $theme object has a $settings property which contains all of the settings for our theme, and finally the settings property contains a variable backgroundcolor that is the value the user entered for that setting. That is how we get a settings value.
 
<code php>
    if (!empty($theme->settings->regionwidth)) {
        $regionwidth = $theme->settings->regionwidth;
    } else {
        $regionwidth = null;
    }
    $css = demystified_set_regionwidth($css, $regionwidth);
 
    if (!empty($theme->settings->customcss)) {
        $customcss = $theme->settings->customcss;
    } else {
        $customcss = null;
    }
    $css = demystified_set_customcss($css, $customcss);
</code>
 
These two routines are nearly identical to the routine above. For both the regionwidth and the backgroundcolor we make sure it has a value and then store it in a variable. We then call the relevant function to make the changes for that setting.
 
Now that we have the general processing function it is time to write the three functions we have used but not written, demystified_set_backgroundcolor, demystified_set_regionwidth, demystified_set_customcss.
 
====The function: demystified_set_backgroundcolor====
 
First up demystified_set_backgroundcolor.
 
<code php>
/**
* Sets the background colour variable in CSS
*
* @param string $css
* @param mixed $backgroundcolor
* @return string
*/
function demystified_set_backgroundcolor($css, $backgroundcolor) {
    $tag = '[[setting:backgroundcolor]]';
    $replacement = $backgroundcolor;
    if (is_null($replacement)) {
        $replacement = '#DDDDDD';
    }
    $css = str_replace($tag, $replacement, $css);
    return $css;
}
</code>
</code>
which means initialise this variable to #FF0 only if it has not been defined already. So because our callback defines variables in the pre SCSS callback - they are available for use anywhere else in our SCSS files.


====The function: demystified_set_regionwidth====
Less is "less good" than SCSS - so it's variables don't have this flexibility. For Less and CSS it's recommended that you would define a "csspostprocess" callback to insert the variables. There is an example of this in the "more" theme.


Next we have the demystified_set_regionwidth function.
''theme/more/config.php''
<code php>
<code php>
/**
$THEME->csspostprocess = 'theme_more_process_css';  
* Sets the region width variable in CSS
*
* @param string $css
* @param mixed $regionwidth
* @return string
*/
function demystified_set_regionwidth($css, $regionwidth) {
    $tag = '[[setting:regionwidth]]';
    $doubletag = '[[setting:regionwidthdouble]]';
    $replacement = $regionwidth;
    if (is_null($replacement)) {
        $replacement = 200;
    }
    $css = str_replace($tag, $replacement.'px', $css);
    $css = str_replace($doubletag, ($replacement*2).'px', $css);
    return $css;
}
</code>
</code>


====The function: demystified_set_customcss====
''theme/more/lib.php''
 
The final function that we need to write is the demystified_set_customcss function.
<code php>
<code php>
/**
function theme_more_process_css($css, $theme) {
* Sets the custom css variable in CSS
    // This is not the exact code from theme_more - it has been simplified.
*
    $customcss = $theme->settings->customcss;             
* @param string $css
     $tag = '[[setting:customcss]]';                                                                                                
* @param mixed $customcss
     $replacement = $customcss;                                                                                                    
* @return string
     if (is_null($replacement)) {                                                                                                  
*/
         $replacement = '';                                                                                                        
function demystified_set_customcss($css, $customcss) {
     }                                                                                                                              
     $tag = '[[setting:customcss]]';
                                                                                                                                   
     $replacement = $customcss;
     $css = str_replace($tag, $replacement, $css);                                                                                  
     if (is_null($replacement)) {
                                                                                                                                   
         $replacement = '';
     return $css;                                        
     }
     $css = str_replace($tag, $replacement, $css);
     return $css;
}
}
</code>
</code>


And that is it no more PHP... Hallelujah I can hear you yelling. The final thing we need to do is tell our theme about the functions we have written and put the settings tags into the CSS.
So this is replacing all instances of  
 
===Finishing it all off===
 
So there are two things we have to do in order to complete this section and have our the settings page implemented and our settings being used.
 
First we need to tell our theme that we want to use the function demystified_process_css as the csspostprocess function. This is done very simply by adding the following line of PHP to our theme's config.php file (theme/demystified/config.php).
 
<code php>
$THEME->csspostprocess = 'demystified_process_css';
</code>
 
With that done the only thing left is to add the settings tag into the CSS. Remember those settings tags are:
; <nowiki>[[setting:backgroundcolor]]</nowiki> : We need to add this where ever we want the background colour setting to be used.
; <nowiki>[[setting:regionwidth]]</nowiki> : We need to add this where ever we want to set the width of the block regions.
; <nowiki>[[setting:customcss]]</nowiki> : We need to add this to the bottom of the CSS file that we want the custom CSS added to.
 
So lets make those changes in CSS now, open up you core.css file and replace the CSS with the CSS below:
<code css>
<code css>
/** Background color is a setting **/
html {background-color:[[setting:backgroundcolor]];}
body {margin:30px;padding:0;border:1px solid #333;border-width:0 10px 0 10px;background-color:#333;}
body #page {background-color:#FFF;position:relative;top:-10px;}
.block .header {background-image:none;background-color:#0C5CAC;border:1px solid #0C5CAC;color:#FFF;}
.block {border-color:#4BA7FF;background-color:#DDEEFF;}
.block .content {background-color:#F1F8FF;}
a:link,
a:visited {color:#0C5CAC;}
a:hover {color:#C77500;}
#page #page-header {background-color:#0C5CAC;margin:0;padding:0;width:100%;color:#fff;}
#page #page-header a:link, #page #page-header a:visited {color:#FFAC02}
#page #page-header .navbar, #page #page-header .navbar a:link, #page #page-header .navbar a:visited {color:#0C5CAC;}
/** Override the region width **/
#page-content #region-main-box {left:[[setting:regionwidth]];}
#page-content #region-main-box #region-post-box {margin-left:-[[setting:regionwidthdouble]];}
#page-content #region-main-box #region-post-box #region-pre {width:[[setting:regionwidth]];left:[[setting:regionwidth]];}
#page-content #region-main-box #region-post-box #region-post {width:[[setting:regionwidth]];}
#page-content #region-main-box #region-post-box #region-main-wrap #region-main {margin-left:[[setting:regionwidthdouble]];}
/** Custom CSS **/
[[setting:customcss]]
[[setting:customcss]]
</code>
</code>
with the value of the admin setting in all CSS from the theme.


You will notice that <nowiki>[[setting:backgroundcolor]]</nowiki> has been used for the html tags background color:
''theme/more/style/custom.css''
<code css>
<code css>
html {background-color:[[setting:backgroundcolor]];}
/* Custom CSS Settings                                                                                                             
-------------------------*/                                                                                                       
[[setting:customcss]]
</code>
</code>


We have also set the width of the block regions by adding <nowiki>[[setting:regionwidth]]</nowiki> as the width for region-pre and region-post as shown below:
This setting is included in one of the style sheets for the theme.
<code css>
#page-content #region-main-box {left:[[setting:regionwidth]];}
#page-content #region-main-box #region-post-box {margin-left:-[[setting:regionwidthdouble]];}
#page-content #region-main-box #region-post-box #region-pre {width:[[setting:regionwidth]];left:[[setting:regionwidth]];}
#page-content #region-main-box #region-post-box #region-post {width:[[setting:regionwidth]];}
#page-content #region-main-box #region-post-box #region-main-wrap #region-main {margin-left:[[setting:regionwidthdouble]];}
</code>
You'll notice here that we have to set several different width and margins using the regionwidth setting and make use of the special regionwidthdouble setting that we added.
 
The final thing that we did was add the <nowiki>[[setting:customcss]]</nowiki> to the bottom of the file to ensure that the custom CSS comes last (and therefore can override all other CSS).
 
And with that we are finished. The screenshot below shows how this now looks in the browser if I set the background colour setting to <span style='background-color:#FFA800'>#FFA800</span> and made the column width 240px;
 
[[Image:Theme.settings.page.04.png|715px|thumb|left|Our settings in action]]


==Using the settings within our layout files==
== What about an image upload setting? ==


==The monster that we have just created==
Theme photo includes examples of image upload settings. Read [[Creating a theme based on boost]] for a detailed explanation of how this theme was created including how to add image upload settings and apply them in SCSS.


==Common pitfalls and useful notes==
==See also==


==More information==
* [[Adding theme upgrade code]]
* [[Themes 2.0]]
* [[Themes 2.0 creating your first theme]]
* [[Themes 2.0 overriding a renderer]]
* [[Styling and customising the dock]]

Revision as of 05:00, 1 December 2016

This document looks at how to create a settings page for your Moodle theme and how to make use of those settings within the CSS and layout files for your theme.

Before we begin

If you want to "code along" with this tutorial - start by downloading this theme and unzipping it to your theme folder.

This is a working example of a theme with some settings extending "Boost". You will need to be using Moodle 3.2 as the Boost theme is only available for this version of Moodle. The information in this tutorial is still valid for versions before 3.2.

We will add some more settings to this theme and explain how to use the settings in the layout files and in the SCSS for this theme.


settings.php

Themes define their settings and add them to the administration pages in their "settings.php". The code that builds all of the admin settings looks for this file in every installed plugin (not just themes).

In the example theme we can see a settings.php file created already - lets see what it's doing.

// This line protects the file from being accessed by a URL directly. defined('MOODLE_INTERNAL') || die();

We put this in all php files that are not meant to be accessed directly. It prevents someone from typing the url to one of these files and accidentally running some code or seeing a strange error.

// This is used for performance, we don't need to know about these settings on every page in Moodle, only when // we are looking at the admin settings pages. if ($ADMIN->fulltree) {

As the comment says, we don't need to build the whole list of settings on every single page in Moodle - only when we are actually browsing through the admin settings pages. So we don't create these settings unless they are needed on this page.

   // Boost provides a nice setting page which splits settings onto separate tabs. We want to use it here.                         
   $settings = new theme_boost_admin_settingspage_tabs('themesettingphoto', get_string('configtitle', 'theme_photo'));

In order to create any settings in our theme, we need to create the setting, and we need to add it to a settings page.

Normally before including the settings.php file for a plugin Moodle will create a variable named $settings which is an instance of the "admin_settingspage" class. In the plugin, settings can be added to the page by using $settings->add(). In this theme we do something special though - we replace the default $settings variable with a new one which has new functionality (tabs).

This theme_boost_admin_settingspage_tabs class is defined in the boost theme (theme/boost/classes/admin_settingspage_tabs.php) and we can use it in boost or any theme that inherits from boost. It will probably be moved in to core so it can be used by any theme very soon because it is very useful.

So $settings is our settings page that we can add things to.

   // Each page is a tab - the first is the "General" tab.                                                                         
   $page = new admin_settingpage('theme_photo_general', get_string('generalsettings', 'theme_photo'));      
   ...
   // Create some settings and add them to $page with $page->add().
   ...
   // Must add the page after defining all the settings!                                                                           
   $settings->add($page);  

To create each tab in this theme_boost_admin_settingspage_tabs class - we create a new settings pages, add all the settings to them and then add each one with $settings->add(). Each page will display as a separate tab.

If we were not using tabs we could just create each setting and add it to the page with $settings->add().

To create a setting we create a subclass of the admin_setting class. These settings are all defined in lib/adminlib.php so you can search and find the right kind of setting.

The constructors for each of the settings classes tend to use similar arguments (but check the docs for each one to be sure).

Example:

   $setting = new admin_setting_configtext('theme_photo/textsetting', get_string('textsetting','theme_photo'), get_string('textsetting_desc', 'theme_photo'), 'defaultvalue', PARAM_NOTAGS, 50);                                                               
   // Any setting that should cause the CSS to be recompiled should have this callback.
   $setting->set_updatedcallback('theme_reset_all_caches');                                                    
   // We are using tabs, so add this to page. If we were not using tabs this would be $settings->add($setting);
   $page->add($setting);

The first 4 arguments for all these settings are always the same - the last ones are specific to the type of setting. Explaining each one in order.

  • theme_photo/textsetting - This is the name of the setting. It starts with the component name for the plugin - then / - then the unique name of the setting in this plugin.
  • get_string('textsetting', 'theme_photo') - This is the name of the setting that will be displayed to the admin. We use a lang string so it can be translated.
  • get_string('textsetting_desc', 'theme_photo') - This is the description of the setting that will be displayed to the admin. We use a lang string so it can be translated. We name this string the same as the name of the setting with _desc at the end. This is recommended so the related strings show up together in the translation website.
  • defaultvalue - This is the default value of the setting and the install / upgrade for your plugin will set this value in the database automatically.

The rest of the arguments are specific to the admin_setting_configtext class. They are:

  • PARAM_NOTAGS - This is the type of text that should be validated in this setting. It can be any of the PARAM values defined in lib/moodlelib.php.
  • 50 - This is the size of the field. Things like URLs should have a longer setting so all of the text will be visible.

How does my setting get saved? It is stored in the mdl_config_plugins table as text and can be retrieved in any php code with:

  $value = get_config('theme_photo', 'textsetting');

What kinds of settings exist?

There are heaps - some of the most useful are listed here:

  • admin_setting_configtext - The most flexible setting, the user enters text.
  • admin_setting_configtextarea - General text area without html editor. Useful for things like raw CSS
  • admin_setting_confightmleditor - A full html editor using the systems default text editor. Good for editing HTML
  • admin_setting_configpasswordunmask - Works like a password field - but isn't one. Good for shared secrets etc
  • admin_setting_configfile - Good for listing a file stored on the server. Does not allow uploading files
  • admin_setting_configexecutable - More specific version of admin_setting_configfile. The file is checked to make sure it can be executed by the webserver
  • admin_setting_configcheckbox - Are you cool [ ]
  • admin_setting_configselect - Choose from a list of values
  • admin_setting_configstoredfile - Allow uploading of files and storing in moodle file storage
  • admin_setting_configcolourpicker - Interactive colour picker

Add a setting and use it in SCSS (or less or css)

Lets add a new setting and show how to use the value of the setting in our SCSS, less or css.

First - we will add a new colour setting to our settings page.

theme/photo/settings.php

   $name = 'theme_photo/cardbg';                                                                                                   
   $title = get_string('cardbg', 'theme_photo');                                                                                   
   $desc = get_string('cardbg_desc', 'theme_photo');                                                                               
   $setting = new admin_setting_configcolourpicker($name, $title, $desc, '#ffffff'); 
   $setting->set_updatedcallback('theme_reset_all_caches');                                                    
   $page->add($setting);

Copy this new setting into the settings.php for theme_photo.

theme/photo/lang/en/theme_photo.php $string['cardbg'] = 'Content background'; $string['cardbg_desc'] = 'A setting to control the background colour for content.';

Add the lang strings to the language file for the theme.

Now clear your caches and you should see the new setting show up on the settings page for this theme (which ever tab you added it to).

This is good - we can change the setting and the value is saved - but it doesn't do anything yet.

In this case we want to use this new setting to set the value of a bootstrap variable.

In theme_photo we do not define any value for the $THEME->prescsscallback which means it will be using the callback from the parent theme which is "theme_boost_get_pre_scss". If we look in the lib.php file from boost too see what this callback is doing we will see it is getting the value of the 'brandcolor' setting and using it to set a SCSS variable named 'brand-primary'. In our theme we want to do the same thing, but for the 'cardbg' setting as well.

theme/photo/config.php $THEME->prescsscallback = 'theme_photo_get_pre_scss';

theme/photo/lib.php function theme_photo_get_pre_scss($theme) {

   global $CFG;                                                                                                                    
                                                                                                                                   
   $scss = ;                                                                                                                     
   $configurable = [                                                                                                               
       // Config key => [variableName, ...].                                                                                       
       'brandcolor' => ['brand-primary'],                                                                                          
       'cardbg' => ['card-bg'],                                                                                                    
   ];                                                                                                                              
                                                                                                                                   
   // Prepend variables first.                                                                                                     
   foreach ($configurable as $configkey => $targets) {                                                                             
       $value = isset($theme->settings->{$configkey}) ? $theme->settings->{$configkey} : null;                                     
       if (empty($value)) {                                                                                                        
           continue;                                                                                                               
       }                                                                                                                           
       array_map(function($target) use (&$scss, $value) {                                                                          
           $scss .= '$' . $target . ': ' . $value . ";\n";                                                                         
       }, (array) $targets);                                                                                                       
   }                                                                                                                               
                                                                                                                                   
   // Prepend pre-scss.                                                                                                            
   if (!empty($theme->settings->scsspre)) {                                                                                        
       $scss .= $theme->settings->scsspre;                                                                                         
   }                                                                                                                               
                                                                                                                                   
   return $scss;                                                                                                                   

}

This is a good way to create SCSS variables for use in your theme. Variables work well in SCSS because they can be defined as $myvariable: #FF0 !default; which means initialise this variable to #FF0 only if it has not been defined already. So because our callback defines variables in the pre SCSS callback - they are available for use anywhere else in our SCSS files.

Less is "less good" than SCSS - so it's variables don't have this flexibility. For Less and CSS it's recommended that you would define a "csspostprocess" callback to insert the variables. There is an example of this in the "more" theme.

theme/more/config.php $THEME->csspostprocess = 'theme_more_process_css';

theme/more/lib.php function theme_more_process_css($css, $theme) {

   // This is not the exact code from theme_more - it has been simplified.
   $customcss = $theme->settings->customcss;               
   $tag = 'setting:customcss';                                                                                                 
   $replacement = $customcss;                                                                                                      
   if (is_null($replacement)) {                                                                                                    
       $replacement = ;                                                                                                          
   }                                                                                                                               
                                                                                                                                   
   $css = str_replace($tag, $replacement, $css);                                                                                   
                                                                                                                                   
   return $css;                                         

}

So this is replacing all instances of setting:customcss

with the value of the admin setting in all CSS from the theme. 

theme/more/style/custom.css /* Custom CSS Settings


*/

setting:customcss

This setting is included in one of the style sheets for the theme.

What about an image upload setting?

Theme photo includes examples of image upload settings. Read Creating a theme based on boost for a detailed explanation of how this theme was created including how to add image upload settings and apply them in SCSS.

See also