Skip to main content
Version: master

Moodle 4.3 developer update

This page highlights the important changes that are coming in Moodle 4.3 for developers.

Database table and column names

Starting with Moodle 4.3 the limits for both table and column names have been raised. Now table names can be up to 53 characters long (from previous 28 characters limit) and column names can be up to 63 characters long (from previous 30 characters limit).

caution

In order to achieve the above, the maximum length for the database prefix ($CFG->prefix) is now 10 characters. Installation or upgrade won't be possible with longer prefixes.

caution

If you are writing a plugin intended for older versions of Moodle then you must continue to use the lower limits of 28, and 30.

Activity badge

The new activity card design proposed for Moodle 4.3 differentiates badge information from other HTML content (displayed using the pre-existing afterlink feature). A new core_courseformat\output\activitybadge class has been added to let modules extend it to display any content in a badge near the activity name. Some considerations about its main features:

  • The badge content is always plain text (no HTML).
  • The badge style can be set (by default is initialized with badge-none, but it can be set by any module).
  • An optional URL to redirect the user when the badge is clicked.
  • An optional ID to add the element in case the module wants to add some JS to the badge events.
  • Optionally, any other extra HTML attributes to the badge element (for example, data attributes).
Afterlink vs ActivityBadge

The content of the afterlink feature has been moved to the end of the activity card so modules using it should check this new feature which might fit better.

Plugins can implement mod_PLUGINNAME\output\courseformat\activitybadge that extends from the original core_courseformat\output\activitybadge class that has been added from Moodle 4.3 onwards. This new class will delegate most data attributes to protected methods, so plugins will only need to implement the update_content() method, to set these attributes accordingly: content, style, url, elementid and extrattributes.

course/format/classes/output/activitybadge.php
namespace core_courseformat\output;

abstract class activitybadge implements named_templatable, \renderable {

/** @var array Badge defined styles. */
public const STYLES = [
'none' => 'badge-none',
'dark' => 'badge-dark',
'danger' => 'badge-danger',
'warning' => 'badge-warning',
'info' => 'badge-info',
];

/** @var cm_info The course module information. */
protected $cminfo = null;

/** @var string The content to be displayed in the activity badge. */
protected $content = null;

/** @var string The style for the activity badge. */
protected $style = self::STYLES['none'];

/** @var \moodle_url An optional URL to redirect the user when the activity badge is clicked. */
protected $url = null;

/** @var string An optional element id in case the module wants to add some code for the activity badge (events, CSS...). */
protected $elementid = null;

/**
* @var array An optional array of extra HTML attributes to add to the badge element (for example, data attributes).
* The format for this array is [['name' => 'attr1', 'value' => 'attrval1'], ['name' => 'attr2', 'value' => 'attrval2']].
*/
protected $extraattributes = [];

[...]

abstract protected function update_content(): void;

}

As a proof of concept, this feature has been implemented by:

  • Forum, to display the unread messages.

    mod/forum/classes/output/courseformat/activitybadge.php
    namespace mod_forum\output\courseformat;

    class activitybadge extends \core_courseformat\output\activitybadge {

    protected function update_content(): void {
    global $CFG;

    require_once($CFG->dirroot . '/mod/forum/lib.php');

    if (forum_tp_can_track_forums()) {
    if ($unread = forum_tp_count_forum_unread_posts($this->cminfo, $this->cminfo->get_course())) {
    if ($unread == 1) {
    $this->content = get_string('unreadpostsone', 'forum');
    } else {
    $this->content = get_string('unreadpostsnumber', 'forum', $unread);
    }
    $this->style = self::STYLES['dark'];
    }
    }
    }
    }
  • Resource, to show the file type (extension). The rest of the resource information (size and creation date) has been kept in the afterlink section.

    mod/resource/classes/output/courseformat/activitybadge.php
    namespace mod_resource\output\courseformat;

    class activitybadge extends \core_courseformat\output\activitybadge {

    protected function update_content(): void {
    $options = (object) ['displayoptions' => $this->cminfo->customdata['displayoptions']];
    $this->content = resource_get_optional_filetype($options, $this->cminfo);
    }
    }

A new core_courseformat/local/content/cm/activitybadge template has been also created to display this activity badge data. As usual, it can be overridden by any format plugin.

JavaScript String fetchers

Since 4.3

New string fetchers were introduced in MDL-79064:

  • getString - fetch a single string, resolving in a Native Promise
  • getStrings - fetch a set of strings, resolving in an array of Native Promises

Note: These new fetchers will return a native Promise rather than a jQuery Promise.

The get_string and get_strings methods have not been deprecated at this time but work is underway to allow for their future deprecation.

Native Promises vs jQuery Promises

The use of jQuery Promises is discouraged in Moodle as they have a different behaviour in some cases:

  • native Promises do not have the done method. Please use then instead
  • native Promises do not have the fail method. Please use catch instead

Please note that the behaviour of catch differs from the jQuery fail. The catch method will return a resolved Promise, whist the fail method will not.

You are strongly advised to convert all uses of .done, and .fail in your code to .then, and .catch as appropriate.

Moodle 4.3 brings a number of improvements to Modal dialogues. These improvements focus on:

  • the declaration of new Modal types
  • the instantiation of new Modal instances
  • the use of instantiated Modals

Conversion of Modal to ESM Class

Since 4.3

If using a prototypal class, you will see an error message such as the following:

Errors shown when trying to instantiate a prototypal modal
test.js:4 Uncaught TypeError: Class constructor Modal cannot be invoked without 'new'
at new MyModal (test.js:4:11)
at <anonymous>:1:1

All modal types must now be written as an ESM class. Prototypal modals are no longer supported.

These changes are backwards compatible with previous versions of Moodle. An ESM Modal definition can be used with Moodle 4.2 or earlier. A prototypal modal cannot be used with Moodle 4.3 onwards.

The same content converted to an ESM class

An ESM class can extend either another ESM class, or a prototypal method.

export default class MyModal extends Modal {
static TYPE = 'mod_example/myModal';

constructor(root) {
// We can override the constructor to call additional setup.
super(root);

this.myCustomMethod();
}

registerEventListeners() {
// Call the registerEventListeners method on the parent class.
super.registerEventListeners();

this.getModal().on(CustomEvents.events.activate, function(e) {
// ...
});
}

myCustomMethod() {
// ...
}
}

Registration helper

Since 4.3

Moodle 4.3 introduces a new registerModalType method on the Modal class to aid in registering a modal.

Compatibility with Moodle 4.2 and older

If your code is intended to work with Moodle 4.2 and older, then you must continue to use the old method of registration. This legacy method will be maintained until Moodle 4.6.

A modal using the new shortcut helper

The shortcut helper for Modal registration is suitable for Moodle 4.3 onwards.

export default class MyModal extends Modal {
static TYPE = 'mod_example/myModal';
static TEMPLATE = 'mod_example/my_modal';
}

MyModal.registerModalType();

Forms API

add_sticky_action_buttons

A new method add_sticky_action_buttons() has been added to Forms API to enable sticky footer.

public function add_sticky_action_buttons(
bool $cancel = true,
?string $submitlabel = null,
);

filter_shown_headers

A new method filter_shown_headers() has been added to to Forms API to show some expanded headers only and hide the rest.

This method adds values to _shownonlyelements array to decide whether a header should be shown or hidden. Only header names would be accepted and added to _shownonlyelements array. Headers included in _shownonlyelements will be shown expanded in the form. The rest of the headers will be hidden.

public function filter_shown_headers(array $shownonly): void {
$this->_shownonlyelements = [];
if (empty($shownonly)) {
return;
}
foreach ($shownonly as $headername) {
$element = $this->getElement($headername);
if ($element->getType() == 'header') {
$this->_shownonlyelements[] = $headername;
$this->setExpanded($headername);
}
}
}

Empty _shownonlyelements array doesn't affect header's status or visibility.

/course/editsection.php
$showonly = optional_param('showonly', 0, PARAM_TAGLIST);

[...]

$mform = $courseformat->editsection_form($PAGE->url, $customdata);

$initialdata = convert_to_array($sectioninfo);
if (!empty($CFG->enableavailability)) {
$initialdata['availabilityconditionsjson'] = $sectioninfo->availability;
}
$mform->set_data($initialdata);
if (!empty($showonly)) {
$mform->filter_shown_headers(explode(',', $showonly));
}

Activity completion

Append a suffix to the completion rules

As part of MDL-78516, the Default completion form has undergone a significant rebuild to enhance code reusability and maintainability. To prevent duplicate IDs, a suffix has been introduced to the form elements related to completion rules.

For third-party plugins, an adjustment is needed to incorporate this new suffix, following the approach already taken by core modules.

The primary modification entails editing mod/yourplugin/mod_form.php and applying the suffix to the completion rule elements within all relevant methods. As an example, here are the changes made to the mod/choice module:

    public function add_completion_rules() {
$mform = $this->_form;

$completionsubmitel = $this->get_suffixed_name('completionsubmit');
$mform->addElement('checkbox', $completionsubmitel, '', get_string('completionsubmit', 'choice'));
// Enable this completion rule by default.
$mform->setDefault($completionsubmitel, 1);
return [$completionsubmitel];
}

public function completion_rule_enabled($data) {
return !empty($data[$this->get_suffixed_name('completionsubmit')]);
}

public function data_postprocessing($data) {
parent::data_postprocessing($data);
// Set up completion section even if checkbox is not ticked.
if (!empty($data->completionunlocked)) {
if (empty($data->{$this->get_suffixed_name('completionsubmit')})) {
$data->{$this->get_suffixed_name('completionsubmit')} = 0;
}
}
}

protected function get_suffixed_name(string $fieldname): string {
return $fieldname . $this->get_suffix();
}
caution

Starting from Moodle 4.3, completion rules without the suffix will be phased out from the Default completion form until they are updated to incorporate the required suffix

User preferences in JavaScript modules

As part of MDL-62859 and MDL-76974, new methods for the reading and writing of user preferences in JavaScript modules have been created.

The core_user/repository module exports new methods getUserPreference, getUserPreferences, setUserPreference and setUserPreferences. Examples of which are below:

Get user preferences

import Notification from 'core/notification';
import {getUserPreference, getUserPreferences} from 'core_user/repository';

// Get single preference.
getUserPreference('mod_example_foo')
.then(window.console.log)
.catch(Notification.exception);

// Get multiple preferences.
getUserPreferences()
.then(window.console.log)
.catch(Notification.exception);
Set user preferences

import Notification from 'core/notification';
import {setUserPreference, setUserPreferences} from 'core_user/repository';

// Set single preference.
setUserPreference('mod_example_foo', 42)
.catch(Notification.exception);

// Set multiple preferences.
setUserPreferences([
{name: 'mod_example_foo', value: 42},
{name: 'mod_example_bar', value: 43},
]).catch(Notification.exception);

Icons

MIME

info

The MIME icons located in the pix/f directory, have undergone an update. These icons, previously available in various sizes, have now been replaced with SVG versions.

To streamline the variety of icons associated with different MIME types, several specific MIME icons have been replaced. Instead, their corresponding generic icons have been integrated from the existing collection, leading to a more efficient representation:

  • avi -> video
  • base -> database
  • bmp -> image
  • html -> markup
  • jpeg -> image
  • mov -> video
  • mp3 -> audio
  • mpeg -> video
  • png -> image
  • quicktime -> video
  • tiff -> image
  • wav -> audio
  • wmv -> video

The subsequent MIME icons have been entirely removed:

  • clip-353
  • edit
  • env
  • explore
  • folder-open
  • help
  • move
  • parent
danger

Files utilizing any of these removed icons will now be represented by the "unknown" icon.

Behat

Removal of Goutte and Goutte Mink Driver

The goutte behat mink driver has been replaced by the browserkit one because the former has been abandoned.

The change should be completely transparent for (near) everybody. Only if you are using some custom-generated behat.yml file or other configuration alternatives different from the Moodle default one, then, any goutte browser occurrence needs to be changed to browserkit_http when configuring the behat mink extension.

See MDL-78934 for more details and changes applied.

Removal of the --skip-passed option

The legacy (and custom) Behat --skip-passed option has been removed completely. Please, use the standard --rerun option that provides exactly the same (execution of failed scenarios only).

Enrolment methods support in CSV course upload

As part of MDL-78855 new methods have been created for enrol_plugin to explicitly mark those enrolment methods that are supported in CSV course upload

Example below for method to be supported:

CSV supported
public function is_csv_upload_supported(): bool {
return true;
}

Also a new method has been created for enrol_plugin to create enrolment instance with custom settings

Add custom instance
public function add_custom_instance(stdClass $course, ?array $fields = null): ?int {
return $this->add_instance($course, $fields);
}

In MDL-73839 cohort enrolment method has been updated to support CSV course upload.