Moodle 4.0 developer update

From MoodleDocs

Moodle 4.0 This page highlights the important changes that are coming in Moodle 4.0 for developers. Including how the UX improvements impact custom themes, relevant API changes, and what you can do as developer to prepare for the 4.0 release.

Theme changes

The 4.0 theme changes can be classified as changes to improve overall navigation, changes for the course navigation and page, and general UI improvements for Moodle 4.0 and newer only.

Navigation UI changes

A new layout has been added that pushes the blocks region offscreen called the drawers layout. This layout has a fixed width of 800px for the main content area and page buttons to open / close the drawers. Files:


In case a page uses “fake blocks” (for example book, quiz, calendar, etc.) the drawer region will be opened automatically on first visit.

Child themes implementing this layout should update the theme config.php and configure the ‘drawers’ layout from theme boost for pages like ‘course’ and ‘incourse’

Pages that should not use the drawers layout are the admin pages or other pages that require more horizontal space in the main content area.

Primary / secondary navigation

The top navbar now includes the new primary navigation, this navigation used to be in the page navdrawer region. If custommenu items are configured in the global theme settings they will be added to the primary navigation.

The main content area shows tabs for secondary navigation with a maximum of 5 items being rendered in this ‘more’ menu. A new UI component has been created to render menus like this. Files:

Navigation upcoming changes
Edit switch.


On theme boost the “Turn editing on” and  “Customise this page” buttons have been replaced by an edit switch in the top navbar. Theme Classic will keep using the old buttons. Child themes can choose to use the edit switch if the theme config.php is using this variable

$THEME->haseditswitch = true;

The languague menu, which used to be rendered in place of the custom menu has moved to the user dropdown when the user is logged in. If not logged in it will be placed next to the search / notification / messaging icon in the top navbar.

Course navigation and the course page

Introduction of a new course index component

The new course index feature can be themed using a set of scss variables. Use them to change the look and feel instead of adding custom css


With the introduction of the course index component, the previous and next links shown underneath each activity are no longer needed and they will be removed.

Introduction of a new activity component


The activities in a course are rendered using a new activity UI component. The activities will use a new renderable and can be customised using a single mustache template

The icons used for activities have been redesigned and use a monochrome svg icon. If contrib plugins provide an icon-mono.svg in their pix folder this icon will be rendered. For example :


The background colour for this icon can be styled using css in a plugin styles.css. Please use one of the theme variables for your icon background using:

.modtype_myplugin .inlineiconsvg {
    background-color: var(--activitytypea);

To customize all icon colours use this scss array and add it to the ‘Raw initial SCSS’ in the theme Boost advanced settings page

The complete array can be overridden using the ‘Raw initial SCSS’ in the theme settings page

$activity-icon-colors: (
    "typea": #5D63F6,
    "typeb": #11A676,
    "typec": #EB66A2,
    "typed": #F7634D,
    "typee": #399BE2,
    "typef": #A378FF

General UI improvements upcoming changes

Login page


The login page has been redesigned and allows the admin to configure a background image for the login page only in the theme settings page. This change is available in both Boost and Classic. The login page still has all the features with an improved layout.

The page footer


In large screens, the page footer button is only visible when clicking a help button at the bottom right of the screen.

User initials as profile picture placeholder


If users do not upload a profile picture the user initials are displayed on a rounded gray background as a placeholder picture in the top navbar or any other page using a placeholder image. This change will be available in both Boost and Classic.

With the introduction of this placeholder image the full username will no longer be displayed in the top navbar.

Image editable component, single image formfield


When uploading a user image or course image the user can now resize and crop the image. This feature can be reused for any component handling images using a new formfield:


This form-field will store a drawer file in the user context. On submitting the form the uploaded file needs to be stored in a more permanent location. The best way of achieving this is creating an image handler class to store / delete / handle form data. For example:


The image editable component can be used as a standalone feature too using


When used as a standalone component it will allow users to change the profile picture from the user profile page, or update any other image used in a custom plugin or theme.

Removal of back to top link


The "back to top" link will be removed for theme boost since the new course index reduced the dependence on page scrolling. Also, the new footer is positioned where this component used to be.

Styling changes

By default rounded edges will be used for UI components MDL-72455, for the page header and main content area the borders will be removed MDL-72457.

Component library

Purpose of the Component Library

Each Moodle installation now ships with a Moodle User Interface (UI) Component library, a documentation system used to describe all the Bootstrap components and the custom Moodle components. The component Library is a helper tool for developers when creating user interfaces, a testing tool for theme developers and a documentation tool for core developers. The ultimate goal of having a component library is to encourage developers to create consistent user interfaces to improve Moodle’s overall user experience.

The library contains pages with documentation about User Interface components. It contains details on how to use the component, what variations are available and the JavaScript events / options are associated with the component.

When writing on these pages it is possible to render core mustache templates using some custom syntax like this:

{{< mustache template="core/notification_error" >}}
{{< /mustache >}}

You can also call core JavaScript or use HTML examples where the html code and the rendered result are visible in the Component Library. For more info visit the Moodle templates page or the Moodle JavaScript page.

Each page in the library uses the current css from the default theme in your Moodle installation, if you have multiple themes installed and enabled the setting "Allow theme changes on url", the component library will have a theme selector option.

Enabling the Component Library

Component library pages are written in the markdown language. These pages need to be compiled to HTML pages before the Component Library is visible. To compile the pages the server running Moodle needs to have the JavaScript developer tools installed (nodeJs and Grunt)

If your server meets all requirements you can enable the library running

$ npm install
$ grunt componentlibrary

Further installation instructions can be found in the Component Library itself.

The online version of the Component Library

A hosted version of the Component Library can be found here.

Documenting new UI Components

There are no set rules for adding new pages in the component library yet. These rules will need to be written and adopted in the integration process for Moodle code.

As a guideline for making this rules consideration are:

The component library is not about single use components, for example the Moodle grade book (a huge component with many custom features). Or about very common components like buttons, these are already covered by the Bootstrap section of the component library.

New features should be build keeping in mind the UI part needs to be customisable and if possible (and making sense) reusable. And example would be the new page drawers that we are introducing for the Navigation project. Or the custom primary navigation menus where overflowing items are pushed into a More section.


The core Navigation API has been left mostly untouched. The callbacks to all navigation callbacks remains unchanged and will be called as part of the regular 'navigation' and 'settingsnav' initialisation. Some new core classes have been created and exist within a new namespace 'core/navigation' and serves as conduit to rearrange, cherry-pick existing navigation nodes from the navigation/settingsnav trees and display within the respective navigation type. As such, it is highly recommended to provide unique keys for custom navigation nodes as this helps in the cherry-picking / rearranging process within the new classes.

Primary navigation / Primary Output

The primary navigation(the navbar) apart from the existing content will now display links to the Dashboard, My Courses, Site Admin and Course search, by default. You can still add items to the navbar via the 'custom menu' option. This will be displayed within the 'More' menu. We have transitioned the menus to be rendered via templates - refer user_menu.mustache. The lang menu has been moved to reside within the user menu.

New view

All settings for courses/modules will now be displayed as tabs within the module. A predefined set of tabs will be shown with any remaining / newly added ones residing within the 'Course Admin' page. The settings cog will not be shown anymore. It is recommended to review any settings as some might be displayed as tabs and possibly move them to the tertiary navigation as is done in the core activity modules1. At most 5 tabs will be displayed to a user with all the overflow nodes now residing within the 'More' menu. Some of the nodes can be hidden by using the new functions defined.

New API functions
Page API
  • Magic getters to fetch the primary and secondary navs and the primary output.
  • The secondarynav magic getter also checks whether a custom secondary class has been defined within the module's local\views directory. Use this if you want to deviate from the standard secondary nav structure/order.
  • set_secondary_nav - Force override the secondary navigation class
  • has_secondary_navigation_setter - Sets the ‘_hassecondarynavigation’ to indicate whether a page should render the secondary navigation
  • set_show_in_secondary_navigation - whether or not a node should be displayed in the secondary nav. Accepts a single boolean argument
  • set_force_into_more_menu- whether or not to force a node into the 'More' menu. Accepts a single boolean argument
Changing order of tabs in secondary navigation nodes

Apart from the previously mentioned functions, you can also create a custom secondary class as mentioned earlier. This will automatically be picked by getter and used to render the secondary nav within the activity. E.g. mod_assign/local/views/secondary. Note: This is currently only possible on an activity and block level.

Upcoming changes:
  1. 1 - Complete tertiary nav overhaul for core’s modules - MDL-71912. MDL-71913, MDL-71914, MDL-71915
  2. Backwards compatibility for complex deep nested custom navigation. Any custom navigation added by 3rd party devs will now be displayed as flatter structure within a URL select - MDL-72352
  3. New module API to inject common content at the top of a module page. The common content would be the title, description and activity information. This solves 2 issues:
    1. A centralised location where we can handle #2 and inject it into the relevant page
    2. A centralised location where we can inject items particularly activity_information without the need to be replicated in each module.

The core_courseformat subsystem

Most of the logic for rendering and editing a course has been moved to a new subsystem called courseformat. The subsystem is located in "course/format" folder so it includes all the format plugins inside. The methods and modules which are distributed between the course and the course/format folders are now rearranged or refactored to be aligned with the current Moodle coding style.

Mandatory renderer in course formats

Now format plugins renderer is not optional anymore. Legacy formats without a renderer will get a deprecation message but it will continue working however, they should create a new renderer as soon as possible. The section-based format can do it by extending the provided core_courseformat\output\section_renderer class which includes all the necessary methods.

New format base class

The old base_format class (which all plugins extend) is now renamed as core_courseformat\base. The new class provides all the functionally of the previous base_format but it has been refactored to be used as a centralized source of truth for the course rendering. Legacy formats should extend the new class to avoid the deprecation message.

Now, the plugin format class provides information such as:

  • If the page is displaying a single or multiple section
  • Give access to other related format objects like the modinfo, the course record, maximum number of sections...
  • If the format is compatible with features like course index, reactive components, ajax...
  • Other format specifics like the page title, the default section name, default blocks...

The format instance is now the main object output components will use to render a course (see next section for more information).

New course output classes and mustache files

Traditionally, section-based course formats uses print_single_section_page and print_multiple_section_page to render the course content. In Moodle 4.0 most of the course rendering methods are migrated to output components and mustache templates. The old methods will get deprecation messages if they use the old renderer methods.

This is an example of a format rendering a course:

// Get the course format instance.
$format = course_get_format($course);

// Get the specific format renderer.
$renderer = $format->get_renderer($PAGE);

if (!empty($displaysection)) {
    // Setup the format instance to display a single section.

// Create the ouptut instance and render it.
$outputclass = $format->get_output_classname('content');
$widget = new $outputclass($format);

echo $renderer->render($widget);

Format plugins are free to use its own output classes to render a course, or they could override the existing output classes by providing their own implementation. For example, the default output for "content" (as in the previous example) is "core_courseformat\output\local\|content", however, if the plugin has a "format_XXX\output\courseformat\content" class, the $format->class the get_output_class will return the overridden one.

Another important update on course rendering is that now all course structure is rendered using mustache templates instead of the original html_writer methods. Now themes are able to override the course format by providing alternative versions of the mustache files. All core course templates are located in "course/format/templates".

All the new output classes and a guide on how to migrate the current third-party plugins will be available soon.

Course editor javascript modules and frontend components

The majority of the javascript logic related to the course editing is replaced by AMD modules. Because this is a major change in the way courses are edited and rendered, by default format plugins will continue using the previous YUI modules for now. However, formats can start using the new libraries overriding the "$format->supports_components()" method.

Some Moodle 4.0 new features are only available for courses using the new editor library:

  • Edit the course via the course index
  • Creating sections without reloading the course page
  • The new move section/activity modal
  • Native browser drag&drop implementation

The new course editor uses a component-based reactive pattern to keep track of the course changes. The pattern highlights are:

  • The main AMD module "core_crouseformat\courseeditor" maintains a data structure called state.
  • Each UI element is implemented as a Component that observes the course state data and reacts to any data change
  • When any reactive component needs to modify the course, it asks the course editor to execute a mutation. Mutations encapsulate all web services calls and alter the course state data.

The reactive library documentation, as well as the format plugin migration guide, will be available soon.

Other course related 4.0 changes

Two new web services have been added:

  • core_courseformat_get_state: user by the new javascript course editor to get the current course state data (containing the list of sections, activities, and other course-related data)
  • core_courseformat_update_course: to alter the current course content. Each call returns the parts of the course state altered by the action

API changes

Behat changes

To make behat tests more readable and easy to maintain, it is recommended to use the most direct steps to get what the test needs. So since MDL-66335 was integrated, and the step was improved in MDL-72179 is highly recommended to use

I am on the "Activity name" "[modname] activity" page 


I am on the "Activity name" "[modname] activity" page logged in as "user"

instead of navigating to the activity via

I am on "Course" course homepage
I follow "Activity name"

Now that Course index (MDL-71209) is integrated but the project is not stable, these behat steps

I am on "Course" course homepage
I follow "Activity name"

will fail using Boost theme.

The reason for it is that the drawer used in Boost is hiding the course index. So when the test is trying to follow an "Activity name" link, it finds two different links:

  • one in the course index
  • another one in the course main content.

But the first one, the one in the course index, is hidden by the drawer, and the test fails.

However the recommended behat steps

I am on the "Activity name" "[modname] activity" page 


I am on the "Activity name" "[modname] activity" page logged in as "user"

work fine.

Some of the failing behats are fixed in - MDL-71209

For example:

And I am on the "Test assignment name" "assign activity" page logged in as teacher1

instead of:

When I log in as "teacher1"
And I am on "Course" course homepage
And I follow "Test assignment name"

Core plugins review

A few plugins from core Moodle LMS which are no longer or hardly used have been removed and, if appropriate, added to the Moodle plugins directory.

More information about this project, the list of plugins to be removed and the process to follow for keeping them before upgrading to 4.0 can be found in the Core plugins review page.