Note:

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

Creating a theme based on classic

From MoodleDocs

Moodle 3.6


This is a tutorial for how to create a new theme based on the Classic theme.

Moodle 3.7 includes a new core theme named "Classic" which is a starting point for themers wanting to build Moodle theme using a 3 column layout without the Boost navdrawer and settings menus.

Getting started

What is a theme? A theme in Moodle is just another type of plugin that can be developed. Themes are responsible for setting up the structure of each page and have the ability to customise the output of any page in Moodle.

This tutorial is based on a the tutorial https://docs.moodle.org/dev/Creating_a_theme_based_on_boost. You can download it or view the source code for it here: https://github.com/bmbrands/moodle-theme_picture

Choosing a name

Your new theme will need a name. Try and think of something short and memorable - and make sure it is not a name that has already been used by someone else. A quick search on the moodle.org/plugins can save you a lot of work renaming things later.

Lets call our new example theme "brands" as we will add some settings to allow "branding" in various places in Moodle.

Starting files

As a plugin, themes must start with the basic structure of a plugin in Moodle. See https://docs.moodle.org/dev/Tutorial#The_skeleton_of_your_plugin for an overview of the files common to all plugins in Moodle.

Following this guide we can start creating our theme. First we create the folder for the new theme under under "/theme/" folder in the Moodle root directory.

/theme/picture/

Now we need to add some standard plugin files to our theme. First is version.php

/theme/picture/version.php

<?php // Every file should have GPL and copyright in the header - we skip it in tutorials but you should not skip it for real.

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

// This is the version of the plugin. $plugin->version = 2019030400;

// This is the version of Moodle this plugin requires. $plugin->requires = 2018051700;

// This is the component name of the plugin - it always starts with 'theme_' // for themes and should be the same as the name of the folder. $plugin->component = 'theme_picture';

// This is a list of plugins, this plugin depends on (and their versions). $plugin->dependencies = [

   'theme_classic' => 2018120700

];

// This is a stable release. $plugin->maturity = MATURITY_STABLE;

// This is the named version. $plugin->release = 1.0;

We also need a language file so that all our strings can be translated into different languages. The name of this file is the component name of our plugin and it sits in the lang/en/ folder for our plugin. We can include translations of our plugin, but we can also provide translations via the https://lang.moodle.org/ website once our plugin has been published to the plugins database at http://www.moodle.org/plugins/.

/theme/picture/lang/en/theme_picture.php

<?php // Every file should have GPL and copyright in the header - we skip it in tutorials but you should not skip it for real.

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

// A description shown in the admin theme selector. $string['choosereadme'] = 'Theme picture is a child theme of the Classic. It adds the ability to upload background photos.'; // The name of our plugin. $string['pluginname'] = 'Picture'; // We need to include a lang string for each block region. $string['region-side-pre'] = 'Left'; $string['region-side-post'] = 'Right';

Theme specific files

Theme plugins have a few more standard files they need to define.

Themes require a favicon file to show in the address bar. See [Favicon].

pix/favicon.ico

(Image file not shown).

Themes also require an example screenshot to be displayed in the theme selector.

pix/screenshot.jpg

(Image file not shown).

Themes require a lib.php file. This file contains callbacks used by various API's in Moodle. Initially this file can be empty, but as we add features to our theme we will need to add some functions here.

lib.php <?php

// Every file should have GPL and copyright in the header - we skip it in tutorials but you should not skip it for real.

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

// We will add callbacks here as we add features to our theme.

Theme config goes in a config.php file. This is one of the most important files in our theme. Once we add this file we will be ready to test our theme for the first time.

config.php

<?php // This file is part of Moodle - http://moodle.org/ // // 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/>.

/**

* Picture config.
*
* @package   theme_picture
* @copyright 2016 Damyon Wiese
* @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

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

// $THEME is defined before this page is included and we can define settings by adding properties to this global object.

// The first setting we need is the name of the theme. This should be the last part of the component name, and the same // as the directory name for our theme. $THEME->name = 'picture';

// This setting list the style sheets we want to include in our theme. Because we want to use SCSS instead of CSS - we won't // list any style sheets. If we did we would list the name of a file in the /styles/ folder for our theme without any css file // extensions. $THEME->sheets = [];

// This is a setting that can be used to provide some styling to the content in the TinyMCE text editor. This is no longer the // default text editor and "Atto" does not need this setting so we won't provide anything. If we did it would work the same // as the previous setting - listing a file in the /styles/ folder. $THEME->editor_sheets = [];

// This is a critical setting. We want to inherit from theme_classic because it provides a great starting point for SCSS bootstrap4 // themes. We have added add more than one parent here to inherit from multiple parents, and if we did they would be processed in // order of importance (later themes overriding earlier ones). Things we will inherit from the parent theme include // styles and mustache templates and some (not all) settings. $THEME->parents = ['boost', 'classic'];

// A dock is a way to take blocks out of the page and put them in a persistent floating area on the side of the page. // does not support a dock so we won't either - but look at bootstrapbase for an example of a theme with a dock. $THEME->enable_dock = false;

// This is an old setting used to load specific CSS for some YUI JS. We don't need it in Classic based themes because Classic // provides default styling for the YUI modules that we use. It is not recommended to use this setting anymore. $THEME->yuicssmodules = array();

// Most themes will use this rendererfactory as this is the one that allows the theme to override any other renderer. $THEME->rendererfactory = 'theme_overridden_renderer_factory';

$THEME->prescsscallback = 'theme_picture_get_pre_scss';

// Since we are using 2 parent themes the correct location of the layout files needs to be define. For this theme we need the multiple // column layouts. $THEME->layouts = [

   // Most backwards compatible layout without the blocks - this is the layout used by default.
   'base' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array(),
   ),
   // Standard layout with blocks, this is recommended for most pages with general information.
   'standard' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre', 'side-post'),
       'defaultregion' => 'side-pre',
   ),
   // Main course page.
   'course' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre', 'side-post'),
       'defaultregion' => 'side-pre',
       'options' => array('langmenu' => true),
   ),
   'coursecategory' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre'),
       'defaultregion' => 'side-pre',
   ),
   // Part of course, typical for modules - default page layout if $cm specified in require_login().
   'incourse' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre'),
       'defaultregion' => 'side-pre',
   ),
   // The site home page.
   'frontpage' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre', 'side-post'),
       'defaultregion' => 'side-pre',
       'options' => array('nofullheader' => true),
   ),
   // Server administration scripts.
   'admin' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre'),
       'defaultregion' => 'side-pre',
   ),
   // My dashboard page.
   'mydashboard' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre', 'side-post'),
       'defaultregion' => 'side-pre',
       'options' => array('nonavbar' => true, 'langmenu' => true, 'nocontextheader' => true),
   ),
   // My public page.
   'mypublic' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre'),
       'defaultregion' => 'side-pre',
   ),
   'login' => array(
       'theme' => 'boost',
       'file' => 'login.php',
       'regions' => array(),
       'options' => array('langmenu' => true),
   ),
   // Pages that appear in pop-up windows - no navigation, no blocks, no header.
   'popup' => array(
       'theme' => 'classic',
       'file' => 'contentonly.php',
       'regions' => array(),
       'options' => array('nofooter' => true, 'nonavbar' => true),
   ),
   // No blocks and minimal footer - used for legacy frame layouts only!
   'frametop' => array(
       'theme' => 'classic',
       'file' => 'contentonly.php',
       'regions' => array(),
       'options' => array('nofooter' => true, 'nocoursefooter' => true),
   ),
   // Embeded pages, like iframe/object embeded in moodleform - it needs as much space as possible.
   'embedded' => array(
       'theme' => 'classic',
       'file' => 'embedded.php',
       'regions' => array()
   ),
   // Used during upgrade and install, and for the 'This site is undergoing maintenance' message.
   // This must not have any blocks, links, or API calls that would lead to database or cache interaction.
   // Please be extremely careful if you are modifying this layout.
   'maintenance' => array(
       'theme' => 'classic',
       'file' => 'maintenance.php',
       'regions' => array(),
   ),
   // Should display the content and basic headers only.
   'print' => array(
       'theme' => 'classic',
       'file' => 'contentonly.php',
       'regions' => array(),
       'options' => array('nofooter' => true, 'nonavbar' => false),
   ),
   // The pagelayout used when a redirection is occuring.
   'redirect' => array(
       'file' => 'embedded.php',
       'regions' => array(),
   ),
   // The pagelayout used for reports.
   'report' => array(
       'theme' => 'classic',
       'file' => 'columns.php',
       'regions' => array('side-pre'),
       'defaultregion' => 'side-pre',
   ),
   // The pagelayout used for safebrowser and securewindow.
   'secure' => array(
       'theme' => 'classic',
       'file' => 'secure.php',
       'regions' => array('side-pre'),
       'defaultregion' => 'side-pre'
   )

];

// This is the function that returns the SCSS source for the main file in our theme. We override the boost version because // we want to allow presets uploaded to our own theme file area to be selected in the preset list. $THEME->scss = function($theme) {

   return theme_picture_get_main_scss_content($theme);

};

Ready set go!

If you have been following along - now we are at the point where we can actually install and test our new theme. Try it now by visiting the admin notifications page to install the new plugin, and then choosing the new theme from the theme selector.

[Theme selector]

When you choose the new theme - you will find that it looks exactly the same as Classic. At this point with our minimal configuration - we are inheriting almost everything from our parent theme including styles and templates. You will notice though that we don't inherit the settings from our parent theme. If you choose a different preset in Classic - it is not applied in this child theme.


Thats it for this tutorial, but there are more Themes docs to browse.