Note: You are currently viewing documentation for Moodle 3.7. Up-to-date documentation for the latest stable version of Moodle may be available here: Theme changes in 2.0.

Development:Theme changes in 2.0: Difference between revisions

From MoodleDocs
m (Typo: plugins->exluded_sheetes)
 
(35 intermediate revisions by 3 users not shown)
Line 1: Line 1:
{{Work in progress}}
{{Infobox Project
|name = Theme changes
|state = Implementation
|tracker = MDL-20204
|discussion = [http://moodle.org/mod/forum/discuss.php?d=140089 HEADS UP: Major theme changes landing]
|assignee = [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]] + feedback and ideas from other developers
}}
{{Moodle 2.0}}
{{Moodle 2.0}}


* '''PROJECT STATE: Proposal'''
* '''MAIN TRACKER ISSUE''': MDL-20204
* '''DISCUSSION AND COMMENTS''': http://moodle.org/mod/forum/discuss.php?d=131219
* '''AUTHOR''': [[User:Petr Škoda (škoďák)|Petr Škoda (škoďák)]] + feedback and ideas from other developers
* '''TIME NEEDED FOR IMPLEMENTATION''': mostly implemented, prototype ready for review
''Please note this is a work in progress, do not edit - use page comments instead if needed, thanks.''


=Goals=
=Goals=
Line 13: Line 14:
# easier theme customisations - both CSS and images
# easier theme customisations - both CSS and images
# simplify core and themes code
# simplify core and themes code
# improve performance
# significant performance improvements
# solve majority of browser caching problems
# solve majority of browser caching problems
# use YUI CSS foundation
# use YUI CSS foundation
# full template support - no templates in core yet though
# allow themes to be stored in separate directory without www access (such as dataroot)
# allow themes to be stored in dataroot (optional in future)


It should be easy to upgrade simple older themes. I think it is better if old themes are completely disabled with reasonable fallback mechanism. Why should we display broken themes during upgrade? Imagine users or teachers can select "broken" themes in the course edit page or a profile, I think it is more professional to display only new and upgraded themes in selectors instead of pretending old themes will work 100%. We have to make sure old themes will not cause fatal white screen errors.
It should be easy to upgrade simple older themes. I think it is better if old themes are completely disabled with reasonable fallback mechanism. Why should we display broken themes during upgrade? Imagine users or teachers can select "broken" themes in the course edit page or a profile, I think it is more professional to display only new and upgraded themes in selectors instead of pretending old themes will work 100%. We have to make sure old themes will not cause fatal white screen errors.
Line 23: Line 23:
=Design overview=
=Design overview=


All theme files are served through two files ''/theme/styles.php'' and ''/theme/image.php''. If more advanced themes need extra javascript files we could add an optional ''/theme/javascript.php'' file and a new config option with list of JS files. This approach allows us to parse the resulting CSS and replace all image placeholders and theme settings with current values.
All theme files are served through two files ''/theme/styles.php'' and ''/theme/image.php''. More advanced themes may serve extra javascript files through the ''/theme/javascripts.php'' file and a new config option with list of JS files. This approach allows us to parse the resulting CSS and replace all image placeholders and theme settings with current values.




Line 45: Line 45:
|-
|-
| lang/
| lang/
| Folder with standard language files - name of theme, usage information, settings. Standard themes store lang files in /lang/.
| Folder with standard language files - name of theme, usage information, settings. Standard themes store lang files in /lang/ for now.
|-
|-
| layout/
| layout/*.php
| Folder with page layout templates
| Folder with page layout templates
|-
|-
Line 59: Line 59:
| Folder with overridden plugin icons - structure is typeofplugin/pluginname/ which maps to pix folder in plugins
| Folder with overridden plugin icons - structure is typeofplugin/pluginname/ which maps to pix folder in plugins
|-
|-
| pix_yui/ (optional)
| style/*.css
| Folder with overridden YUI CSS images, maps to /lib/yui/assets/sam/
| Style sheet files referenced from the config.php.
|-
| template/
| Folder with template files - structure is typeofplugin/pluginname/templatename.php which maps to pix folder in plugins
|-
|-
| config.php
| config.php
| Theme configuration - see bellow.
| Theme configuration - see bellow.
|-
| favicon.ico
| Site icon.
|-
|-
| lib.php (optional)
| lib.php (optional)
Line 79: Line 73:
| settings.php (optional)
| settings.php (optional)
| Custom theme settings - colours, logos, etc. Settings are applied in custom css post-processing function.
| Custom theme settings - colours, logos, etc. Settings are applied in custom css post-processing function.
|-
| styles_*.css (optional)
| Style sheet files.
|-
|-
| version.php
| version.php
Line 89: Line 80:
==Theme config.php==
==Theme config.php==


The theme config.php structure is simplified and a bit more flexible. The goal is to make overriding of parent themes simple and easy to understand.
The theme config.php structure is simplified and a bit more flexible. The goal is to make overriding of parent themes simple and easy to understand. Please note global $THEME variable is not available any more, use theme property in current page instance instead.




<code php>$THEME->parents = array('standard', 'purple');</code>
<code php>$THEME->parents = array('standard', 'purple');</code>
Lists all parents top-down, each theme contains the full list of parents, this is non-recursive and more flexible specification without any limits. Originally the number of parent levels was restricted.
Lists all parents top-down, each theme contains the full list of parents, this is non-recursive and more flexible specification without any limits. Originally the number of parent levels was restricted.
<code php>$THEME->sheets = array('styles_layout', 'styles_fonts', 'styles_color');</code>
The same as before, lists files from current theme directory.




<code php>$THEME->parents_exclude_sheets('standard'=>array('styles_moz'), 'purple'=>array('styles_fonts'));</code>
<code php>$THEME->parents_exclude_sheets('standard'=>array('styles_moz'), 'purple'=>array('styles_fonts'));</code>
It is also posssible to use ''true'' instead of array in order to specify ''all'' sheets or all sheets in all parents, if not specified the value from the parent theme is used.
It is also posssible to use ''true'' instead of array in order to specify ''all'' sheets or all sheets in all parents, if not specified the value from the parent theme is used.
<code php>$THEME->sheets = array('styles_layout', 'styles_fonts', 'styles_color');</code>
The same as before, lists files from current theme directory.




Line 113: Line 104:


<code php>$THEME->layouts = array(...);</code>
<code php>$THEME->layouts = array(...);</code>
The complete list of themes is in theme/standard/config.php. Page layouts are in fact high level templates that are using PHP syntax. The template files are stored in template/ subdirectory. Each page layout has specification of block areas and link to template file. Themes may also reference template files from other themes.
The complete list of layouts is in theme/base/config.php. Page layouts are in fact high level templates that are using PHP syntax. The template files are stored in layout/ subdirectory. Each page layout has specification of block areas and link to template file. Themes may also reference layouts files from other themes.




Line 121: Line 112:


<code php>$THEME->rendererfactory = 'standard_renderer_factory';</code>
<code php>$THEME->rendererfactory = 'standard_renderer_factory';</code>
The same as before. It is the name of class that returns needed instances of core and plugin renderers.
The same as before. It is the name of class that returns needed instances of core and plugin renderers. defined in core some library or theme/themename/lib.php or theme/themename/renderers.php




<code php>$THEME->csspostprocess = 'csspostprocess';</code>
<code php>$THEME->csspostprocess = 'csspostprocess';</code>
Name of custom CSS post-processing function, this function is usually defined in theme/themename/lib.php.
Name of custom CSS post-processing function, this function is usually defined in theme/themename/lib.php.
<code php>
$THEME->javascripts = array('navigation');
$THEME->javascripts_footer = array('someJSlibrary');
</code>
List of extra javascript files that are included on each page. Themes can not include extra scripts from the theme folder because the folder may not be accessible via web.


=Implementation=
=Implementation=
Line 132: Line 130:
==One huge CSS sheet==
==One huge CSS sheet==


Each page includes only one huge style sheet. The URL is returned from ''$OUTPUT->theme_stylesheet_url($encoded)'' function. All theme sheets are served by a /theme/styles.php script. Page parameters specify the theme name and revision.
Each page includes only one huge style sheet. All theme sheets are served by a /theme/styles.php script. Page parameters specify the theme name and revision.


The CSS concatenation is done from the YUI CSS, styles.css from all plugins and theme style sheets starting with top most parent and current theme last, please note the order is very important. The algorithm is following:
The CSS concatenation is done from the YUI CSS, styles.css from all plugins and theme style sheets starting with top most parent and current theme last, please note the order is very important. The algorithm is following:
# YUI CSS
# YUI2 CSS
## merge all YUI CSS into one file, respect correct order of files
## merge all YUI2 CSS into one file, respect correct order of files
## inject image placeholders instead of relative links <nowiki>[[pix:yui|someimage]]</nowiki>
# plugins CSS
# plugins CSS
## go through all plugins and search for styles.css - put the list into array, use component names as keys, locations as values
## go through all plugins and search for styles.css - put the list into array, use component names as keys, locations as values
## filter out excluded sheets specified in current $THEME->plugins_exluded_sheetes
## filter out excluded sheets specified in current $THEME->plugins_exclude_sheets
# theme CSS
# theme CSS
## go through all sheets defined in all parents and store all $THEME->sheets in array
## go through all sheets defined in all parents and store all $THEME->sheets in array
## filter out excluded sheets specified in current $THEME->parent_exluded_sheetes
## filter out excluded sheets specified in current $THEME->parent_exclude_sheets
# resolve real image locations
# resolve real image locations
## regex search for <nowiki>[[pix:componentname|imagewithsibdirnoext]]</nowiki>
## regex search for <nowiki>[[pix:componentname|imagewithsibdirnoext]]</nowiki>
Line 150: Line 147:
# apply theme admin settings - values and image locations
# apply theme admin settings - values and image locations


Please note that the current $PAGE->requires->css() is suitable mostly for user supplied CSS for data content such as the custom CSS used in mod/data.
Please note that the current $PAGE->requires->css() is suitable mostly for user supplied CSS for data content such as the custom CSS used in mod/data/ module.
 
The YUI3 reset CSS is loaded separated before this huge combined CSS stylesheet, YUI3 loader may load CSS on the fly from Javascript.


==Theme caching==
==Theme caching==
Line 164: Line 163:
* theme revision
* theme revision


The theme revision is stored in $CFG->themerevision, it is an integer counter incremented after installation/upgrade of any plugin or core. The revision value -1 is used in theme designer mode to prevent the caching completely.
The theme revision is stored in $CFG->themerev, it is an integer counter incremented after installation/upgrade of any plugin or core. The revision value -1 is used in theme designer mode to prevent the caching completely.




Line 177: Line 176:
This mode also disables all CSS cleanup and compression, all comments are kept and extra debug information can be included in CSS.
This mode also disables all CSS cleanup and compression, all comments are kept and extra debug information can be included in CSS.


This setting should be available from the Appearance settings page.
This setting is available from the Appearance settings page.


==Performance improvements==
==Performance improvements==
Line 190: Line 189:
==Browser hacks==
==Browser hacks==


Old meta.php was used mostly for conditional loading of IE specific hacks. Open university developed alternative solution which adds browser specific classes to body html element. This can be implemented in the pagelib method returning standard body tags.
Old meta.php was used mostly for conditional loading of IE specific hacks. Open University developed alternative solution which adds browser specific classes to body html element. This can be implemented in the pagelib method returning standard body tags.


  <body class="ie ie7">
  <body class="ie ie7">
Line 220: Line 219:
Moodle started using YUI framework around 1.7, until 2.0dev we did not use any UI widgets that required CSS. The problem is that the YUI needs to be loaded before theme and plugin CSS, second problem is that standard YUI CSS requires reset CSS which greatly improves A-grade browser compatibility and helps theme designers.
Moodle started using YUI framework around 1.7, until 2.0dev we did not use any UI widgets that required CSS. The problem is that the YUI needs to be loaded before theme and plugin CSS, second problem is that standard YUI CSS requires reset CSS which greatly improves A-grade browser compatibility and helps theme designers.


In 2.0dev there was an option to use external YUI library, unfortunately we can not use external CSS because we need to recalculate image links (this allows easy overriding of YUI images without actually overriding the CSS definition.
YUI3 implements new loaders both for CSS and JS, there is a complementing PHP dependency loader for YUI.


===YUI CSS foundation===
===YUI CSS foundation===


Why should we base our themes on YUI CSS foundation? Why not? The benefits are:
Moodle styles are based on YUI foundation? Why not? The benefits are:
* eliminates some different HTML defaults (margins, paddings, font sizes, etc.) [http://developer.yahoo.com/yui/reset/ (YUI CSS Reset)]
* eliminates some different HTML defaults (margins, paddings, font sizes, etc.) [http://developer.yahoo.com/yui/reset/ (YUI CSS Reset)]
* consistent font sizing and better font-family degradation [http://developer.yahoo.com/yui/fonts/ (YUI CSS Fonts)]
* consistent font sizing and better font-family degradation [http://developer.yahoo.com/yui/fonts/ (YUI CSS Fonts)]
* incredibly simple table-less page layouts that include nesting [http://developer.yahoo.com/yui/fonts/ (YUI CSS Grids)]
* the standard YUI CSS is already built on top of this foundation
* the standard YUI CSS is already built on top of this foundation
* incredibly simple table-less page layouts that include nesting [http://developer.yahoo.com/yui/fonts/ (YUI CSS Grids)] (optional, themes do not have to use it for layout)
 
I do not think we should expect any problems related to the use of YUI CSS foundation, it looks like the current themes need only minor tweaking to make it compatible (already tested).
 
Core and custom themes could use the extremely simple and powerful YUI CSS Grids framework for page layout. I do not think we could quickly develop anything as reliable and compatible before the release of 2.0.
 
If we do not use this foundation we have to write all CSS for standard YUI widgets, this could be very time consuming and the results/timeframe are not predictable.


===YUI widgets customisation===
===YUI widgets customisation===


The standard YUI CSS has to be loaded after YUI CSS Base (Reset+Fonts+Grids), but before our own CSS. The CSS may be overridden through plugin styles.css or theme styles. YUI standard images could be simply changed by adding different images with the same name into ''theme/standard/yui_pix/..'' or any other theme. The image resolver would first look into current theme, all parents and the last option would be standard YUI library
The standard YUI CSS has to be loaded after YUI CSS Base (Reset+Fonts+Grids), but before our own CSS. Overriding of YUI stylesheets should not depend on the order of loading, we only guarantee that the YUI CSS foundation sheets are loaded before any other CSS, customisations of YUI skins has to use moodle class selectors.


===YUI versioning===
===YUI versioning===


In 1.9 we store all YUI files in /lib/yui/ folder, this may be a potential problem when upgrading YUI version from upstream because the old files could be still cached in browsers. Solution could be to add version number /lib/yui/x.yy/.
In 1.9 we store all YUI files in /lib/yui/ folder, this was a problem when upgrading to YUI version from upstream because the old files could be still cached in browsers.
 
In 2.0 we are finally replicating the YAHOO directory structures, each new version is stored in separate directory.


===Combination of YUI 2 and 3===
===Combination of YUI 2 and 3===
YUI 3 uses JS autoloading which is a great step forward and simplification. Unfortunately we still need the YUI2 libraries around for some time, luckily YUI2 libraries may coexist with YUI3 code.


==The image resolver==
==The image resolver==
Line 256: Line 253:
* /theme/themename/pix/ - theme images
* /theme/themename/pix/ - theme images
* /theme/themename/pix_core/ - overridden images from core /pix/ folder
* /theme/themename/pix_core/ - overridden images from core /pix/ folder
* /theme/themename/pix_yui/ - overriding of yui images from themes
* /theme/themename/pix_plugins/plugin/plugintype/ - overriding of plugin images in themes
* /theme/themename/pix_plugins/plugin/plugintype/ - overriding of plugin images in themes




The standard API is <code>$OUTPUT->image_url($componentname, $imagename, encoded)</code> when used from PHP and <nowiki>[[pix:componentname|imagename]]</nowiki> if used in CSS.
The standard API is <code>$OUTPUT->pix_url($componentname, $imagename, encoded)</code> when used from PHP and <nowiki>[[pix:componentname|imagename]]</nowiki> if used in CSS.
 
There are a few exceptions like theme favicon and screenshots, all other images should be placed in pix directories.




Image resolved allows us to serve images from dataroot via /theme/image.php script and also solves the browser caching issues.
Image resolved allows us to serve images from dataroot via /theme/image.php script and also solves all browser caching issues.


==Themes in dataroot==
==Themes in extra directory==


A frequently requested feature. Some admins might not like this, it should be optional. Some really advanced themes with lots of custom files might not be compatible at first. In fact it does not have to be dataroot, this location could be configurable.
Themes in dataroot is a frequently requested feature. Some admins might not like this, it should be optional. Some really advanced themes with lots of custom files might not be compatible at first. In fact it does not have to be dataroot, this location is configurable via $CFG->themedir.




In the stable branch we have a strange mix of standard themes. The simplified installation and upgrades would allow us to lower the number of themes in official distribution. I think we need only:
In the stable branch we have a strange mix of standard themes. Moodle 2.0 is expected to include following themes:
* standard - basic theme that can be used as base for other themes
* base - bare bones minimal theming that most other themes build on
* customcolor - standard with admin specified colour palette and custom logos
* standard - basic theme that can be used as base for really simple themes (the exact look of new standard theme is not decided yet)
* and one other fancy modern theme like anomaly with multiple configuration settings
* customcolor - standard with admin specified colour palette and custom logos (not confirmed)
* and many other fancy modern themes like anomaly ( optionally with multiple configuration settings)


Other contrib themes would be available via web interface from Moodle configuration.
Other contrib themes could be available via web interface from Moodle configuration in some future Moodle version.


==Admin theme settings==
==Admin theme settings==
Line 290: Line 285:


==Page layout==
==Page layout==
Each page may specify one of standard page layouts that are defined in theme/standard/config.php. It is not possible to add custom layouts.
Each page may specify one of standard page layouts that are defined in theme/base/config.php. It is not possible to add custom layouts.


Layout definition consists of:
Layout definition consists of:
Line 306: Line 301:
Module may define own renderer class and use own renderer methods. Themes may override both core and plugin renderers however you need to have some more advanced understanding of PHP and Moodle design in general.
Module may define own renderer class and use own renderer methods. Themes may override both core and plugin renderers however you need to have some more advanced understanding of PHP and Moodle design in general.


==Templates==
==Templates (maybe in future)==


Similar to page layouts but much smaller parts of UI that are embedded into pages. This is a new feature that is not used in Moodle core yet.
Similar to page layouts but much smaller parts of UI that are embedded into pages. This is a new feature that is not used in Moodle core yet.
Line 315: Line 310:




Please note this does not mean that Moodle is switching to templates now, but technically we could, plugin developers may decide to do so independently.
Please note this does not mean that Moodle is switching to templates now, but technically we could, plugin developers would decide to do so independently. This topic should be revisited in Moodle 2.1dev.


==Other API changes==
==Other API changes==
Line 341: Line 336:
* rename mod/modname/styles.php to styles.css
* rename mod/modname/styles.php to styles.css
* put all images into mod/modname/pix/
* put all images into mod/modname/pix/
* replace $CFG->pixpath with $OUTPUT->image_url('imagename', 'mod_modname')
* replace $CFG->pixpath with $OUTPUT->pix_url('imagename', 'mod_modname')


==Removed features==
==Removed features==
# '''sometheme/meta.php''' - used mostly for IE6/7 hacks, custom layouts may be used instead
# '''sometheme/meta.php''' - used mostly for IE6/7 hacks, custom layouts may be used instead
# '''smartpix''' - completely obsoleted by the new image location resolution algorithm
# '''smartpix''' - completely obsoleted by the new image location resolution algorithm
# $CFG->themewww, $CFG->themedir and friends - themes can be stored in dataroot, web hosting companies may use shared dirroot without custom themes, the styles.php URLs would be always constructed via some helper functions
# '''styles.php''' replaced by styles.css, supported in all plugin types - the PHP syntax is not needed anymore because images are specified using <nowiki>[[pix:component|dir/image]]</nowiki> syntax and we can also use custom css post-processors
# '''styles.php''' replaced by styles.css, supported in all plugin types - the PHP syntax is not needed anymore because images are specified using <nowiki>[[pix:component|dir/image]]</nowiki> syntax and we can also use custom css post-processors
# '''$CFG->pixpath''' replaced by $OUTPUT->image_url()
# '''$CFG->pixpath''' replaced by $OUTPUT->pix_url()
# '''CSS constants''' replaced by the admin theme settings
# '''CSS constants''' replaced by the admin theme settings
# separate IE6 and IE7 sheets - replaced by body class attributes
# separate IE6 and IE7 sheets - replaced by body class attributes
Line 367: Line 361:
| Contrib developer
| Contrib developer
| Has to learn new API and upgrade current code.
| Has to learn new API and upgrade current code.
| New useful pix folder and standard styles.css in all plugins. $OUTPUT->image_url() more flexible then old pixpath.
| New useful pix folder and standard styles.css in all plugins. $OUTPUT->pix_url() more flexible then old pixpath.
|-
|-
| Theme designer
| Theme designer
Line 377: Line 371:
| Much easier installation (optionally in dataroot) and easy customisation without code modification (images and colours for example). Much safer upgrades. Possibility to upgrade theme via web interface. No browser caching issues when upgrading themes. Better performance and lower server load.
| Much easier installation (optionally in dataroot) and easy customisation without code modification (images and colours for example). Much safer upgrades. Possibility to upgrade theme via web interface. No browser caching issues when upgrading themes. Better performance and lower server load.
|}
|}
==See also==
Using Moodle forum discussions:
* [http://moodle.org/mod/forum/discuss.php?d=131219 Yet more theme changes proposal]
* [http://moodle.org/mod/forum/discuss.php?d=140089 HEADS UP: Major theme changes landing]
* [[Development:Output_renderers]]
[[Category:Themes]]

Latest revision as of 06:42, 19 July 2010

Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the page comments.


Template:Infobox Project Template:Moodle 2.0


Goals

The main goals are:

  1. easier theme customisations - both CSS and images
  2. simplify core and themes code
  3. significant performance improvements
  4. solve majority of browser caching problems
  5. use YUI CSS foundation
  6. allow themes to be stored in separate directory without www access (such as dataroot)

It should be easy to upgrade simple older themes. I think it is better if old themes are completely disabled with reasonable fallback mechanism. Why should we display broken themes during upgrade? Imagine users or teachers can select "broken" themes in the course edit page or a profile, I think it is more professional to display only new and upgraded themes in selectors instead of pretending old themes will work 100%. We have to make sure old themes will not cause fatal white screen errors.

Design overview

All theme files are served through two files /theme/styles.php and /theme/image.php. More advanced themes may serve extra javascript files through the /theme/javascripts.php file and a new config option with list of JS files. This approach allows us to parse the resulting CSS and replace all image placeholders and theme settings with current values.


All CSS style sheets (including YUI, plugin CSS and parent themes) are merged into a single large CSS file served via the /theme/styles.php file. This script accepts following parameters:

  • theme (string) - name of the theme
  • rev (int) - theme revision number stored in $CFG->themerevision


All options and features are reviewed and optimised. Backwards compatibility is not a primary concern, future possibilities and easy maintenance are always favoured.

Theme directory structure

File/folder'
'Description
db/ (optional) Installation and upgrade hooks - use of db tables is not recommended.
lang/ Folder with standard language files - name of theme, usage information, settings. Standard themes store lang files in /lang/ for now.
layout/*.php Folder with page layout templates
pix/ Folder with theme pictures - used from CSS or layout only, not used from other plugins.
pix_core/ (optional) Folder with overridden core images and icons from /pix/ folder
pix_plugins/ (optional) Folder with overridden plugin icons - structure is typeofplugin/pluginname/ which maps to pix folder in plugins
style/*.css Style sheet files referenced from the config.php.
config.php Theme configuration - see bellow.
lib.php (optional) Library functions - custom css post-processing, custom render factory, theme init function
renderers.php (optional) Custom renderers used from custom renderer factories.
settings.php (optional) Custom theme settings - colours, logos, etc. Settings are applied in custom css post-processing function.
version.php Needed for install and upgrade hooks, states compatibility with specific Moodle versions. Used for triggering of cache purging.

Theme config.php

The theme config.php structure is simplified and a bit more flexible. The goal is to make overriding of parent themes simple and easy to understand. Please note global $THEME variable is not available any more, use theme property in current page instance instead.


$THEME->parents = array('standard', 'purple'); Lists all parents top-down, each theme contains the full list of parents, this is non-recursive and more flexible specification without any limits. Originally the number of parent levels was restricted.


$THEME->sheets = array('styles_layout', 'styles_fonts', 'styles_color'); The same as before, lists files from current theme directory.


$THEME->parents_exclude_sheets('standard'=>array('styles_moz'), 'purple'=>array('styles_fonts')); It is also posssible to use true instead of array in order to specify all sheets or all sheets in all parents, if not specified the value from the parent theme is used.


$THEME->editor_sheets = array('styles_tinymce'); We can not load the full CSS file into the HTML editor's content area, instead we load editor sheet from lib/editor/editorname/editor_sheets.css and also sheets specified in theme.


$THEME->plugins_exclude_sheets('mod_book', 'gradereport_grader'); Ideally all plugin specific CSS should be stored in styles.css file separately in each plugin. This option lists plugins that should be excluded from this theme, if not specified the value from the parent theme is used.


$THEME->layouts = array(...); The complete list of layouts is in theme/base/config.php. Page layouts are in fact high level templates that are using PHP syntax. The template files are stored in layout/ subdirectory. Each page layout has specification of block areas and link to template file. Themes may also reference layouts files from other themes.


$THEME->resource_mp3player_colors, $THEME->filter_mediaplugin_colors Obsoleted. If not specified the value from the parent theme is used. All these should be moved to real theme settings.


$THEME->rendererfactory = 'standard_renderer_factory'; The same as before. It is the name of class that returns needed instances of core and plugin renderers. defined in core some library or theme/themename/lib.php or theme/themename/renderers.php


$THEME->csspostprocess = 'csspostprocess'; Name of custom CSS post-processing function, this function is usually defined in theme/themename/lib.php.


$THEME->javascripts = array('navigation'); $THEME->javascripts_footer = array('someJSlibrary'); List of extra javascript files that are included on each page. Themes can not include extra scripts from the theme folder because the folder may not be accessible via web.

Implementation

One huge CSS sheet

Each page includes only one huge style sheet. All theme sheets are served by a /theme/styles.php script. Page parameters specify the theme name and revision.

The CSS concatenation is done from the YUI CSS, styles.css from all plugins and theme style sheets starting with top most parent and current theme last, please note the order is very important. The algorithm is following:

  1. YUI2 CSS
    1. merge all YUI2 CSS into one file, respect correct order of files
  2. plugins CSS
    1. go through all plugins and search for styles.css - put the list into array, use component names as keys, locations as values
    2. filter out excluded sheets specified in current $THEME->plugins_exclude_sheets
  3. theme CSS
    1. go through all sheets defined in all parents and store all $THEME->sheets in array
    2. filter out excluded sheets specified in current $THEME->parent_exclude_sheets
  4. resolve real image locations
    1. regex search for [[pix:componentname|imagewithsibdirnoext]]
    2. priority is: current theme, parent themes, then plugin or YUI fodlers
    3. images in web accessible areas are linked directly, images in dataroot would have to go through /theme/image.php?theme=xxx&file=/sub/img&component=moodle&rev=-1
  5. apply theme admin settings - values and image locations

Please note that the current $PAGE->requires->css() is suitable mostly for user supplied CSS for data content such as the custom CSS used in mod/data/ module.

The YUI3 reset CSS is loaded separated before this huge combined CSS stylesheet, YUI3 loader may load CSS on the fly from Javascript.

Theme caching

Potential problems are:

  • server performance - the merging of all CSS, parent themes and image resolving is relatively expensive
  • bandwidth - longer caching, fewer files and optional gzip compression
  • stale data in browser caches - different file needs to be served when anything in CSS changes


The theme CSS content depends on:

  • current theme
  • theme revision

The theme revision is stored in $CFG->themerev, it is an integer counter incremented after installation/upgrade of any plugin or core. The revision value -1 is used in theme designer mode to prevent the caching completely.


All images used both from PHP and CSS have to be cached too. This is handled automatically in /theme/image.php which accepts similar parameters like the styles.php script.

The theme designer mode

Administrator, theme designers and developers often need to tweak CSS or images. In previous versions users had to purge the browser caches manually.

In theme designer mode no CSS is cached on server or in browser, each changes are immediately visible. The switching on of this mode immediately invalidates old caches, the caching is turned on again after switching it off. This mode causes higher server load.

This mode also disables all CSS cleanup and compression, all comments are kept and extra debug information can be included in CSS.

This setting is available from the Appearance settings page.

Performance improvements

There are several possibilities for more performance improvements:

  • storing of final CSS files in dataroot - caches need to be deleted after each theme revision change; this could significantly reduce server load
  • longer lifetimes - revision parameter eliminates the stale CSS in browser cache completely , lower bandwidth consumption
  • gzip compression - faster page loading on first page
  • remove comments and useless white space
  • etc.

Browser hacks

Old meta.php was used mostly for conditional loading of IE specific hacks. Open University developed alternative solution which adds browser specific classes to body html element. This can be implemented in the pagelib method returning standard body tags.

<body class="ie ie7">
#mypage .whatever {
 /** normal rules */
}
.ie6#mypage .whatever {
 /** broken rules */
}

OU used these hacks not only for IE ;-)

RTL support

Originally RTL tweaks were stored in separate files. Now we use the same body class tweaks as described above.

<body class="dir-rtl">
#mypage .whatever {
 /** normal rules */
}
.dir-rtl #mypage .whatever {
 /** RTL rules */
}

YUI

Moodle started using YUI framework around 1.7, until 2.0dev we did not use any UI widgets that required CSS. The problem is that the YUI needs to be loaded before theme and plugin CSS, second problem is that standard YUI CSS requires reset CSS which greatly improves A-grade browser compatibility and helps theme designers.

YUI3 implements new loaders both for CSS and JS, there is a complementing PHP dependency loader for YUI.

YUI CSS foundation

Moodle styles are based on YUI foundation? Why not? The benefits are:

  • eliminates some different HTML defaults (margins, paddings, font sizes, etc.) (YUI CSS Reset)
  • consistent font sizing and better font-family degradation (YUI CSS Fonts)
  • the standard YUI CSS is already built on top of this foundation
  • incredibly simple table-less page layouts that include nesting (YUI CSS Grids) (optional, themes do not have to use it for layout)

YUI widgets customisation

The standard YUI CSS has to be loaded after YUI CSS Base (Reset+Fonts+Grids), but before our own CSS. Overriding of YUI stylesheets should not depend on the order of loading, we only guarantee that the YUI CSS foundation sheets are loaded before any other CSS, customisations of YUI skins has to use moodle class selectors.

YUI versioning

In 1.9 we store all YUI files in /lib/yui/ folder, this was a problem when upgrading to YUI version from upstream because the old files could be still cached in browsers.

In 2.0 we are finally replicating the YAHOO directory structures, each new version is stored in separate directory.

Combination of YUI 2 and 3

YUI 3 uses JS autoloading which is a great step forward and simplification. Unfortunately we still need the YUI2 libraries around for some time, luckily YUI2 libraries may coexist with YUI3 code.

The image resolver

Images are used in html code and in CSS style sheets. The problem is easy to solve in PHP code, partial solution was already present in Moodle 1.9 - see $CFG->pixpath

In 2.0dev there was implemented a new icon_finder class, it can be replaced by much simpler rules, we could also add pix support into all plugins.

Image locations:

  • /mod/modulename/pix/, blocks/blockname/pix/ - in all plugins
  • /theme/themename/pix/ - theme images
  • /theme/themename/pix_core/ - overridden images from core /pix/ folder
  • /theme/themename/pix_plugins/plugin/plugintype/ - overriding of plugin images in themes


The standard API is $OUTPUT->pix_url($componentname, $imagename, encoded) when used from PHP and [[pix:componentname|imagename]] if used in CSS.


Image resolved allows us to serve images from dataroot via /theme/image.php script and also solves all browser caching issues.

Themes in extra directory

Themes in dataroot is a frequently requested feature. Some admins might not like this, it should be optional. Some really advanced themes with lots of custom files might not be compatible at first. In fact it does not have to be dataroot, this location is configurable via $CFG->themedir.


In the stable branch we have a strange mix of standard themes. Moodle 2.0 is expected to include following themes:

  • base - bare bones minimal theming that most other themes build on
  • standard - basic theme that can be used as base for really simple themes (the exact look of new standard theme is not decided yet)
  • customcolor - standard with admin specified colour palette and custom logos (not confirmed)
  • and many other fancy modern themes like anomaly ( optionally with multiple configuration settings)

Other contrib themes could be available via web interface from Moodle configuration in some future Moodle version.

Admin theme settings

Very often users need to make small tweaks to standard themes such as different colour or logos. There should be a way to keep this settings in config_plugin and files separately in dataroot. Settings are placed in /theme/themename/settings.php. This new feature could significantly reduce known theme upgrade problems in the future.

This feature replaces the original CSS constants and will probably use the same syntax. The original CSS constants required modifications in dirroot which was in some cases unacceptable. CSS constants would not be compatible with automatic updates vie web interface anyway.

This feature requires advanced caching of CSS. These settings and files should be available in layouts and renderers too.

The actual replacing of setting placeholders by setting values is performed in custom css post-processing function specified in config.php. Logos and other custom images would be specified as external URLs, later we could also add basic support for storage of these custom theme files in standard Moodle filesystem.

Page layout

Each page may specify one of standard page layouts that are defined in theme/base/config.php. It is not possible to add custom layouts.

Layout definition consists of:

  • template file specification - template name + file name without extension
  • definition of regions
  • default region

New layouts will not be added in the STABLE CVS branches.

Renderers

Renderers are small methods that render visual elements using functional programming - our old style PHP style.


Module may define own renderer class and use own renderer methods. Themes may override both core and plugin renderers however you need to have some more advanced understanding of PHP and Moodle design in general.

Templates (maybe in future)

Similar to page layouts but much smaller parts of UI that are embedded into pages. This is a new feature that is not used in Moodle core yet.

Code developers may choose to use templates instead of renderers for some larger parts of UI, they may also use renderers from templates. The major difference is that templates accept just one $DATA object with all parameters, templates might be also much easier to use&understand for typical theme designers.

The original emulated templates approach was replaced because it was designed for code developers, not designers. I think it is much easier to just copy templates from core or plugins into themes and tweak them, instead of the reverse engineering of the renderers.


Please note this does not mean that Moodle is switching to templates now, but technically we could, plugin developers would decide to do so independently. This topic should be revisited in Moodle 2.1dev.

Other API changes

  • added course layout
  • $PAGE->set_generaltype() replaced by $PAGE->set_pagelayout() because it really switches to one of the layouts from the standard theme; also the complete list of layouts is given in theme/standard/config.php - there is no way to add plugin layouts, the $PAGE->set_pagelayout() is used from core and plugin code, not from themes, so it is not possible to add new layouts at all (and never was)
  • name things moodle_* only if potential conflicts exist, everything plugin related should be named componentname_ (mod_ is usually an exception)- this was discussed several times before; renamed moodle_core_renderer' class to core_renderer, etc.
  • themes are now real plugins with capabilities, lang packs, upgrade code, settings, upgrade code, etc. - it is not recommended to create new db table though

Backwards compatibility and upgrades

BC is very limited, all themes and modules need to be manually updated. Keeping old themes during the upgrade must not cause fatal PHP errors. Old themes can be detected by searching for /theme/oldtheme/styles.php, this file will not be present in the new themes any more. Moodle core would simply use the specified parent theme or the standard theme.

Theme upgrade steps

  1. delete styles.php
  2. redefine all config.php options - in majority of cases change parent value to parents array
  3. rename styles_ie6.css and styles_ie7.css to styles_layout_ie6.css and styles_layout_ie7.css - each normal sheet may have an extra sheet with _ieX suffix now, these are loaded automatically, excluding is applied based on $THEME->parents_exclude_sheets() info from the current theme
  4. rename rtl.css to styles_layout_rtl.css - again each normal style sheet may have extra sheet with _rtl suffix similar to IE hacks sheets
  5. delete header.html, footer.html and meta.php - obsoleted by $THEME->layouts option and new layout files
  6. add custom layouts and rendereds

In order to minimize confusion during the upgrade, the old themes will be ignored and will be listed os "Incompatible" on the theme selection page - this page is probably the first place admins go in order to diagnose theme problems.

Module upgrade steps

  • rename mod/modname/styles.php to styles.css
  • put all images into mod/modname/pix/
  • replace $CFG->pixpath with $OUTPUT->pix_url('imagename', 'mod_modname')

Removed features

  1. sometheme/meta.php - used mostly for IE6/7 hacks, custom layouts may be used instead
  2. smartpix - completely obsoleted by the new image location resolution algorithm
  3. styles.php replaced by styles.css, supported in all plugin types - the PHP syntax is not needed anymore because images are specified using [[pix:component|dir/image]] syntax and we can also use custom css post-processors
  4. $CFG->pixpath replaced by $OUTPUT->pix_url()
  5. CSS constants replaced by the admin theme settings
  6. separate IE6 and IE7 sheets - replaced by body class attributes
  7. separate RTL sheets - replaced by body class attribute

Expected reactions

User type
Negative
Positive
Core developer none No backwards compatibility headaches. Powerful new features. More flexible API.
Contrib developer Has to learn new API and upgrade current code. New useful pix folder and standard styles.css in all plugins. $OUTPUT->pix_url() more flexible then old pixpath.
Theme designer Has to learn new theme API. Old advanced themes has to be completely redesigned. Has to understand YUI CSS foundation. They can finally override core and plugin images. Easier distribution of custom themes. New income opportunity. Basic theme structure is simplified. No browser caching issues when designing themes.
Administrator All themes need to be updated. Old themes are ignored. Much easier installation (optionally in dataroot) and easy customisation without code modification (images and colours for example). Much safer upgrades. Possibility to upgrade theme via web interface. No browser caching issues when upgrading themes. Better performance and lower server load.

See also

Using Moodle forum discussions: