Creating a theme settings page

Revision as of 05:00, 1 December 2016 by Damyon Wiese (talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

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