Code structure

This document provides an outline of code structure within Totara.
It focuses on plugins structure as that is without a doubt the most prevalent area of work for most reading this document, however the same structure applies to components.
Core on the other hand has a more bespoke structure.

Item directories and frankenstyle naming

The earlier document on High level architecture and organisation introduced you to the concepts we use to organise our product.

Every component, plugintype, plugin, subplugin type and subplugin has its own directory within Totara.
The location of that directory will depend upon what it is.
If it is a component or plugintype then it can be anywhere within the directory structure, except within other plugin type and subplugin type directories.
If it is a subplugintype then it will be within the owning plugin.
If it is a plugin or subplugin then it will be within the owning type's directory.

Each of these items has to have a unique name. This is both enforced in code, and in the file system as you cannot have two directories with the same name!

Within the product we need a way in which we can identify and talk about an individual item, whether it is a component, a plugin, or a subplugin.
To do this we use what we call frankenstyle names; they are a concatenation of the the type, and the unique name of an item.

The following provides examples for each to help illustrate how this work.


Core is core, is core.
There is only one, and we refer to it as core.

Frankenstyle name


All components are said to belong to core.
The following is a table illustrating some of the more widely know components.

ComponentFrankenstyle nameDirectory

Plugin types

Plugin types are talked about as top level items, as they are a single parent with many children.
The following table illustrates some of the more often talked about plugin types.

Plugin typeFrankenstyle nameDirectory
Authentication pluginsauth./auth
Course formatsformat./course/format


Plugins must be of a type, and their directory must exist directly within the plugin types directory.
The following table has examples for the three plugin types noted above.

TypePluginFrankenstyle nameDirectory


Authentication plugginManualauth_manual./auth/manual


Course formatWeeksformat_weeks./course/format/weeks


Single activityformat_singleactivity./course/format/singleactivity

You will notice in the above examples that we sometimes have names that are different from the frankenstyle name and directory.
This is important to illustrate, and more often than not arrives from a business decision to change our terminology and how we refer to a item.
In the case of Seminar/Factoface the decision was made to rename it from FaceToFace to Seminar as they more accurately described the functionality in our target markets.
Renaming directories is not something we do, simply put the frankenstyle name that is given to something is used through the system and changing it is not a simple task.
In fact in light of the fact we are open source, maintain a deprecation policy and facilitate extensibility and customisability so extensively it is nigh impossible to rename a directory.
Doing so would have a potentially disaster butterfly effect on our partners and subscribers.

Sub plugin types

These are just like plugin types, except that their directory must exist within a plugins directory structure.
A quick example:

Owning pluginSubplugin typeFrankenstyle nameDirectory

Atto editorPluginatto./lib/editor/atto/plugins

Subplugins are used sparingly within our product. In our core distribution at the time of writing this there are only 15 subplugin types.

Sub plugins

Just like plugins, except these must exist within the subplugin type directory.

Subplugin typeSubpluginFrankenstyle nameDirectory
Atto pluginBoldatto_bold./lib/editor/atto/plugins/bold




The following are the key files you will commonly encounter directly within an items directory.


This is required for all plugins and subplugins.
It contains the following information:

  • Version of the plugin
    Increased when upgrade is required, such as for database schema changes, required data manipulation, changes to language files etc.
  • The required version of the product
    Remember there are a lot of third party plugins out there. This helps ensure when installing a plugin that it is compatible with the version of Totara that you are running.
  • The component
    This is the plugins frankenstyle name and is used to verify the location and name of the plugin during installation and upgrade.
    Makes sure you have things in the right place.

There are a few other things that it can specify, as documented in the developer document.


Nearly all components, plugins and subplugins will have an index.php.
Plugins and subplugins will share an approach to this, however each is free to implement their own functionality.
Its existence benefits security by helping to ensure that incorrectly configured web servers that list directories will have a file to serve by default when a directory is requested.


Contains administrative settings for the plugin. These are included within the main administration structure of the site and bundled into the configuration state by the configuration API.


Contains functions belonging to this component or plugin, but that are used by core, or other components in order to interact with this item in a managed way.
These files used to collect a very large number of functions.
Because the file is intended to serve core and other components it is frequently included from outside of its own scope and context.

This is a legacy approach, our preference now is autoloaded classes that serve specific purposes.
You will find more information on our preferred approach below.


Contains functions for interacting with this item that are designed to be used internally by the item only.
This file will only ever be included by scripts belonging to this item, and should never be included outside of the items scope and context.

This is, like lib.php, a legacy approach, and we now prefer autoloaded classes to serve a specific purpose.


Contain web service definitions and handlers.

Our preferred approach is now to use GraphQL which requires autoloaded, namespaced classes instead of a predetermined root directory file.


Contains an output renderer belonging to this item and that should be used by all entry pages to produce output.
They form the link between the items logic and template system.

Importantly they are factory driven and designed so that they can be overridden by the theme, providing theme developers a means of rewriting and extending the user experience of an item.


Any CSS the plugin or component may want to introduce to a theme.
You may find less, or sass directories containing source used to compile this styles.css file.

It is also possible to have theme specific style files, named styles_{theme_frankenstyle_name}.css.
These are rarely encountered in core as we have control over our themes but are often encountered in third party plugins.


This is a running record of all deprecations, API changes, dev notes occurring within the items scope.
It is a running record maintained by developers at the time that changes are made.
It serves as an excellent reference for anyone maintaining customisations, or working with API's published by the item.


This is an old standard, before class autoloading was available to the platform.
They are form definitions, with * typically matching an entry point in the item.

Our preferred approach is to autoload these from a recognised namespace.


The following is a list of commonly encountered directories and the purpose that they serve.


The most important of all. The classes directory contains autoloadable classes.
The file name and name of a class within this directory is vitally important in order to work with autoloading.
Namespacing is also commonly used, with first level names acting as reserved name spaces for API integrations.
Each namespace block is matched by a directory within the classes directory.

For more information on class autoloading within Totara please refer to our developer documentation.


Contains AMD JavaScript modules.

These will be organised into two sub directories:

  • src - where we make our changes.
  • build - created and updated by running grunt.


Courses, and all item within the course context can contain backup and restore code that is used to export data relating to a specific context (that which is being backed up) and then import code to re-inject it into the product during a restoration.
This is used by the backup API within the product.


Contains key files used to install, upgrade, and define the plugin.
The most notable of which are as follows:

  • install.xml
    The database schema for this item. It should be created by the in product XMLDB editor.
  • install.php
    Code to execute during installation.
  • upgrade.php
    Upgrade steps for this item. Each step maps references a version found in the version.php mentioned above.
  • upgradelib.php
    Extracts upgrade operations into functions in order to facilitate testing and reuse when required.
  • access.php
    Defines the capabilities this item wishes to introduce.
    Used by the core_role component.
  • caches.php
    Defines any caches this item wishes to use.
    Used by the core_cache component.
  • events.php
    Defines event observers that this item has, enabling it to react to those events when they are fired.
  • hooks.php
    Defines hook observers that this item has, enabling it to react to those hooks when they are triggered.
  • renamedclasses.php
    Keeps a list of class names that have been renamed, automatically creating aliases for them and printing a debugging notice is someone tries to use one.
    Required as part of our Deprecation guidelines
  • services.php
    Defines web services published by this item.
  • subplugins.php
    Defines any sub plugins this item introduces.
  • tag.php
    Defines tag collections and areas introduced by this item.


Contains language translations for this item.

All strings within Totara that are presented to the user must come through the translation system.
The definition of those strings exist within this directory.

Within the main distribution you will find only an "en" directory.
In core we only provide english [british english] translation.
Other translations are available for download and installation from our translation system, see our documentation on Internationalisation for more information.


Contains any images the item wants to introduce. These resources are then accessible through our mediation layer and can be overridden by themes.


Contains report builder sources and embedded report definitions.
See our documentation on Report builder for more information.


Contains mustache templates.
These can be overridden by themes.
See our documentation on Mustache templates and 2021-03-09_10-42-44_Output for more information.


Contains automated unit and acceptance tests.

Unit tests must exist directly within this directory, in a file named *_test.php and contains a testcase named frankenstylename_*_testcase that extends advanced_testcase or basic_testcase.
See our documentation on Unit testing for more information.

We use Behat for acceptance testing.
Feature files exist within a "behat" subdirectory.
See our documentation on Acceptance testing for more information.


Contains YUI JavaScript modules.
These are a legacy item, with our preferred approach being either Vue modules, or AMD modules.

See our documentation on JavaScript & AMD modules for more information.


Contains GraphQL schema files for the services this item chooses to publish.