Case study: Upgrading Totara Community theme

As part of our Totara Talent Experience Platform (Totara 13) release strategy, the team at Totara lined up an upgrade of our Community and Academy Themes, during the fuller upgrade process. This page covers the upgrade pathway and learning points encountered during that theme upgrade process, and hopefully serves as a useful reference point for others doing the same. 

Our team have seen a variety of theme implementations from Totara 12 and earlier, so there isn't a "one way to upgrade your theme" set of advice that we can offer. However, there are common areas that we can highlight and this page will also cover those aspects.

Preparing to upgrade to Totara 13

In preparation for the upgrade to T-13, we did a stocktake of what our previous theme contained, including;

  • Minor fixes and tweaks to UX
  • Visual styles and imagery
  • Previous customisations specific to course features, which we have now ported into core for everyone to use
  • Current structure of theme inheritance
  • Any other themes in the project inheriting from the theme we're upgrading

We set aside two weeks (one sprint for us) to understand the scope of the front-end upgrade work, and (crucially) check that the approach lined up with our assumptions based on changes to themeing that we've made between Totara 13 and previous versions.

How the upgrade path unfolded

Identifying specific technology upgrades

As we had decided to upgrade our community theme to be based on Ventura rather than Basis, the following areas were identified as needing to be upgraded:

  • Theme needs to be changed to inherit from Ventura + Legacy instead of Roots/Basis.

  • Legacy is the successor of the deprecated Roots/Basis themes and styles the non-Vue parts of Totara. It is written in SASS so we must also port our custom theme modifications from LESS to SCSS as they use mixins, variables, and so on from the base theme. We won't move our styles to the client directory as that is intended for styling parts of the software rendered in Vue.

  • Most LESS variable overrides will need to become CSS Variable (aka CSS Custom Properties) overrides.

Theme config.php changes

  • `$THEME->parents` changes to `['ventura', 'legacy', 'base']` as we are now based off Ventura
  • `$THEME->minifycss` should be set to false as it is already minified and the PHP-side minification can introduce bugs
  • In `$THEME->parents_exclude_sheets`, the entries for Roots and Basis are replaced by a single entry for Legacy - the entry for Base is kept
  • Remove deprecated `yuicssmodules` setting, which is ignored when Ventura or Legacy are parents
  • Remove references to `settings-noprocess`, as we will be relying on the Ventura Theme Settings UI, introduced in Totara 13

Porting CSS

In the "/server/theme/" folder, we started out by renaming the "less/" folder to "scss/".

The standard structure for the non-Tui part of Totara SCSS themes has an entry point directly under the "scss/" folder, usually named "totara.scss", but could be named anything so long as it is referenced in $THEME->sheets.

Inside "scss/theme/", there are then two files: "variables.scss" containing CSS and SCSS variables defined by the theme, and "styles.scss" containing SCSS rules. Each of these files can import other files.

We started out by moving and renaming "scss/totara.less" to "scss/theme/styles.scss". We also created a "variables.scss" in the same folder (empty for now).

Back in "scss/totara.scss" we then added imports for the files in the following order: parent theme variables, theme variables, parent theme styles, theme styles. This ensures variable modifications get applied in the correct order:

// Variables
@import 'theme_base/flexible-icons';
@import 'theme_legacy/theme/variables';
@import 'theme/variables';

// Styles
@import 'theme_legacy/theme/styles';
@import 'theme/styles';


Now, it's time to start porting the LESS to SCSS. Beginning in "scss/theme/styles.scss", we commented out all of the imports. Next, we went through the file changing all LESS syntax to SCSS. You can try building with Grunt from within "/server/theme/community/" to see any syntax errors at this point, though it will probably complain about missing variables.

Once we've done that and our file only contains valid SCSS, it's time to take a look at the imports. In our Legacy theme implementation of SCSS, imports work a little differently to either LESS or regular SCSS. Imports should omit the ".scss" file extension, and can take one of two forms:

  • Relative import, e.g. `@import '../totara/mod_quiz';` or `@import 'icons';`. The import path here is relative to the current file
  • Absolute import, e.g. `@import 'theme_custom/totara/mod_quiz';`. This works even when importing from another theme, as we do to get the variables and styles from `theme_legacy`

We changed all of the imports to be valid, and then commented them out again as the files do not actually exist yet.

Any pure-variable imports should be moved from "styles.scss" to "variables.scss".

The next step is to go through all of the imports one by one, (starting with the variable imports beforehand), and port them to SCSS – renaming the file to ".scss", the fixing up the syntax inside the file until Grunt no longer complains about syntax errors.

Variable usages are one of the trickier things to port as a lot of variable names have changed in the new theme. The easiest way to find the replacement variable is to find a usage of the original variable name in "/server/theme/roots/", then look up the corresponding file in "/server/theme/legacy/" and see what variable it is using. It may be using either a CSS variable (`var(--name)` syntax) or a SCSS variable (`$name` syntax).

Another gotcha is that while in LESS you can use syntax like `.someclass { div& { color: red; } }` in a selector, in SASS this is invalid syntax. There is a helper we have added to work around that, which looks like this: `.someclass { @include prepend-current('div') { color: red; } }`.

Once porting over all our custom CSS and verifying it works, the next step was porting our colour customisations from setting SCSS variables to setting CSS variables, as these will apply in more places and can be customised in the new Ventura Theme Settings UI.

After removing our old colour variable overrides, we then added some code in "scss/theme/variables.css" setting our new colour customisations. We did this in two ways – the first was setting the high level CSS variables, like `--color-primary` and `--color-state` and its variants like -hover and -focus. The second was setting the equivalent high-level SCSS colour variables like `$boot-color-primary` and `$boot-color-state` and its variants like -hover and -focus, as not all places in the Legacy theme are able to use CSS variables yet.

Additionally, we created a plugin component directory for the theme ("/client/component/theme_community/") and put the same CSS variable overrides in "/client/component/theme_community/src/global_styles/_variables.scss" so that Tui components receive the same colours and the Ventura Theme Settings UI is able to access them. We then added `theme:derive` directives there as well, referencing the ones in "theme_ventura". This allows the theme panel to generate the hover/focus/active variants of colours.

Looking for ways to reduce customisations

During the porting process, we were able to remove a fair amount of style overrides by using better utilising variable overrides, removing workarounds for issues in the old theme, and relying more on the standard styling provided by Ventura + Legacy.

Because the Ventura + Legacy theme has much cleaner variable inheritance structure, we also found ourselves needing far fewer variable overrides to achieve the look we wanted - the entire theme only overrides seven core variables, ten if you include the -hover etc. variants.

Our Community team confirmed that "Collapsible topics with background colours" was a popular feature not only for them, but quite a few customers out there, so we made the move to tidy the customisation up and port it directly into core so that it is available to everyone from Totara 13. Because of this, we were able to move our modifications to `format_topic` and update the custom styling to style the core feature instead.

Making use of new platform features

Previously, runtime theme customisation was implemented using a "settings-noprocess" CSS file that contained placeholders that were replaced at runtime based on customisation in Roots/Basis theme settings UI. This meant a lot of awkward selectors to style all the parts we wanted to update the colours of. Leveraging CSS variables means we can use the new Ventura theme settings UI instead and have everywhere that uses that CSS variable update, now and in the future.

We followed the standard way of enabling the theme settings UI for our upgraded Community theme, as documented in Creating custom themes.

Reflections

  • Improvements in the stock Totara theme in Totara 13 reduced the amount of customisation we needed to do
  • `cd`ing to the `/server/theme/community/` folder and then running Grunt is a lot faster than running Grunt at the root or `/server/` directories
  • Similarly for the `/client/component/theme_community/` plugin component directory, running `npm run tui-build theme_mythemename` (or `npm tui-build-watch` during development) from the root directory is a lot faster than building all of the client components
  • Most of our assumptions on porting our pre-Totara 13 theme to Totara 13 were about right, with exceptions popping up related mostly to syntax differences between LESS and SCSS

Additional resources

As mentioned during the overview for this page, there is no single way to recommend upgrading earlier versions of Totara themes to Totara 13 because many implementations differ. So looking forward, we've created an "Example" theme in a public repository, that demonstrates how to use the Tui framework, while also incorporating previous file structures to ease theme migrations where they still generally align with the example theme.