Transform Learning with a Powerful Enterprise LMS

Learn more
Moodle

Frankenstyle Naming in Moodle: Rules, Examples and Exceptions

What a Moodle frankenstyle component name is, the validation rules in core_component, every place the name appears (tables, capabilities, strings, web services) and the legacy activity module exceptions.

Learn more about this topic with AI

Gemini opens with the prompt copied - paste it into the chat to start.

Illustration of Moodle frankenstyle component names built from a plugin type prefix and folder name, such as mod_forum and block_html

Moodle frankenstyle is the naming convention that gives every plugin and core subsystem one unique machine name: the plugin type prefix, an underscore, then the plugin's folder name in lower case. The quiz activity is mod_quiz, the Text block is block_html, the user upload admin tool is tool_uploaduser, and the course subsystem is core_course. Moodle uses that one string to find the plugin's code, its language strings, its database tables, its capabilities, its settings and its web service functions.

If you write or review Moodle plugins, getting the frankenstyle name right on day one saves a painful rename later, because the name is baked into table names, capability names and stored settings. This reference shows the format, the rules the code actually enforces, every place the name appears, and the exceptions that still trip people up, with examples taken from the core code base.

Checked against the Moodle 5.3.0 source (lib/components.json, public/lib/classes/component.php and public/lib/classes/param.php) and the Moodle developer documentation on frankenstyle and plugin types, October 2026. The rules below have not changed in the 4.x and 5.x branches apart from the reserved qtype_random name noted later.

The format: type prefix plus folder name

A frankenstyle component name has two parts separated by the first underscore:

  1. The plugin type prefix, which says what kind of plugin it is and therefore which directory it lives in. Activity modules use mod, blocks use block, admin tools use tool.
  2. The plugin name, which is exactly the name of the plugin's folder, always in lower case.

Examples from Moodle 5.3, with paths relative to the public/ web root that Moodle has used since 5.1:

ComponentTypeFolderWhat it is
mod_forummodpublic/mod/forumForum activity
block_htmlblockpublic/blocks/htmlText block
tool_uploadusertoolpublic/admin/tool/uploaduserUpload users admin tool
auth_ldapauthpublic/auth/ldapLDAP authentication
qtype_calculatedqtypepublic/question/type/calculatedCalculated question type
format_topicsformatpublic/course/format/topicsCustom sections course format
assignsubmission_fileassignsubmission (subplugin)public/mod/assign/submission/fileFile submissions for Assignment
core_coursecore subsystemnot a pluginCourse subsystem

Notice that the prefix and the directory are not always the same word. Blocks live in blocks/, admin tools in admin/tool/, question types in question/type/. The mapping from prefix to directory is defined in lib/components.json, which in Moodle 5.3 lists 45 plugin types plus one deprecated type (mnetservice). For the full list with what each type does, see our guide to Moodle plugin types.

The naming rules Moodle enforces

The developer docs describe the rules, but the code is what decides whether your plugin loads. Plugin names are checked in core_component::is_valid_plugin_name():

  • Most plugin types must match /^[a-z](?:[a-z0-9_](?!__))*[a-z0-9]+$/. The name starts with a lower-case letter, contains only lower-case letters, digits and single underscores, and ends with a letter or digit. Hyphens and capitals are not allowed.
  • Activity modules must match /^[a-z][a-z0-9]*$/: no underscores at all. The source comment is blunt about why: component normalisation "would break very badly otherwise".
  • An activity module cannot share its name with a core subsystem. A module called course or grades would be indistinguishable from core_course or core_grades when written in short form.
  • qtype_random is reserved. The random question type was removed from core, and the validator rejects that name because backup and restore still give it special handling.

A plugin whose folder name breaks these rules is not reported with an error. The plugin types documentation says it plainly: such a plugin "will be silently ignored". If a new plugin never appears on the Plugins overview page and the upgrade screen does not offer to install it, check the folder name before anything else.

Full component names are validated separately by clean_param() with PARAM_COMPONENT. That check accepts only normalised names, rejects double underscores, and rejects any mod_ name with more than one underscore. Use it when a component name arrives from user input:

$component = clean_param($rawcomponent, PARAM_COMPONENT);
if ($component === '') {
    throw new \moodle_exception('invalidcomponent', 'error');
}

Treat this snippet as illustrative: it is not run on a live site; test on staging first.

Core subsystems and how short names are resolved

Core subsystems are not plugins, but they have frankenstyle names too: core_ plus the subsystem name, for example core_course, core_user, core_grades or core_reportbuilder. Moodle 5.3 lists 80 subsystems in lib/components.json.

Older code and some APIs still accept short names, and core_component::normalize_component() turns them into a type and name pair using these rules:

InputResultWhy
moodle, core or an empty stringcoreThe core component itself
course (no underscore, a known subsystem)core_courseMatches a subsystem name
forum (no underscore, not a subsystem)mod_forumAnything else without an underscore is treated as an activity module
moodle_coursecore_courseThe moodle type is rewritten to core
block_htmlblock_htmlSplit on the first underscore

That fallback is the reason activity modules cannot contain underscores and cannot reuse subsystem names. It is also why get_string('lockupdated', 'forum') still works in core JavaScript: forum normalises to mod_forum. In new code, always write the full name. core_component::normalize_componentname() returns the normalised string, and core_component::get_component_directory() returns the plugin's absolute path.

Where the frankenstyle name appears

Once you pick a name, it shows up in at least a dozen places. Examples are from core plugins in 5.3:

PlacePatternExample
version.php$plugin->component$plugin->component = 'block_html';
Language filelang/en/{component}.phpblocks/html/lang/en/block_html.php
StringsSecond argument of get_string()get_string('pluginname', 'block_html')
Autoloaded classesNamespace under classes/\mod_forum\local\..., \tool_uploaduser\...
CapabilitiesUnderscore becomes a slashmod/forum:viewdiscussion, block/html:addinstance
Database tablesFrankenstyle name as table prefixblock_recentlyaccesseditems, tool_dataprivacy_request
Plugin settingsplugin column of config_pluginsget_config('tool_task', 'lastcronstart')
Web service functionsFunction name prefixmod_forum_get_forums_by_courses
Mustache templates{component}/{template}mod_forum/discussion_list
JavaScript modules{component}/{module}mod_forum/discussion_list from amd/src/discussion_list.js
Global functions and constantsPrefix, upper case for constantslocal_example_do_thing(), LOCAL_EXAMPLE_LIMIT
CLI scriptsComponent argumentsphp admin/cli/cfg.php --component=tool_recyclebin, php admin/cli/uninstall_plugins.php --plugins=mod_assign
PHPDoc@package@package mod_forum

The coding style now says non-namespaced classes named with the frankenstyle prefix (mod_forum_example) are deprecated in favour of namespaced ones (\mod_forum\example). Global functions and constants are discouraged in favour of autoloaded classes and class constants, but when you do need them they must carry the prefix.

The activity module exceptions

Activity modules are the oldest plugin type, and three legacy shortcuts survive:

  • Tables drop the mod_ prefix. The forum's tables are forum, forum_posts and so on, not mod_forum_posts.
  • The language file drops the prefix. It is mod/forum/lang/en/forum.php, while a block's is block_html.php.
  • lib.php callbacks use the bare module name. Moodle calls forum_add_instance() and forum_supports(). The frankenstyle docs allow modulename_ as a function prefix for modules for backwards compatibility.

Everything newer uses the full name even for modules: the \mod_forum namespace, the mod/forum:... capabilities, the mod_forum/... templates and JavaScript modules, and $plugin->component = 'mod_forum' in version.php.

Subplugins

Some plugins define their own plugin types. Assignment declares them in mod/assign/db/subplugins.json: the type assignsubmission lives in mod/assign/submission and assignfeedback in mod/assign/feedback. A subplugin's frankenstyle name uses that type as its prefix, so the file submission plugin is assignsubmission_file, with the language file lang/en/assignsubmission_file.php.

Because normalize_component() treats any unknown prefix as a possible subplugin type, a typo in a subplugin prefix does not fail loudly. Check names against the parent's subplugins.json.

Worked example: naming a new local plugin

Say you are building company-specific reports as a local plugin and choose the name acmereports. Every name follows from that choice:

ItemName
Componentlocal_acmereports
Folder (Moodle 5.1 and later)public/local/acmereports
Language filelang/en/local_acmereports.php
Namespace\local_acmereports, classes under classes/
Tableslocal_acmereports, local_acmereports_runs
Capabilitylocal/acmereports:view
Web service functionlocal_acmereports_get_report
Template and JavaScript modulelocal_acmereports/report

The minimum version.php:

<?php
defined('MOODLE_INTERNAL') || die();

$plugin->component = 'local_acmereports';
$plugin->version   = 2026103100;
$plugin->requires  = 2026100500; // Moodle 5.3; set to the oldest release you support.
$plugin->maturity  = MATURITY_ALPHA;
$plugin->release   = '0.1.0';

This file is not run on a live site; test on staging first, and set requires from the root version.php of the oldest Moodle release you support (2026100500 is 5.3). Moodle uses $plugin->component during install and upgrade to confirm the code sits in the right folder, so a mismatch between this value and the directory stops the install or upgrade with a misplaced-plugin error.

Two naming choices are worth making deliberately. Avoid underscores in the plugin name even where they are allowed: the PARAM_COMPONENT docblock notes that numbers and underscores are "strongly discouraged". And if you may publish the plugin, check the Moodle Plugins directory first, because the directory requires a unique frankenstyle name and will not accept a duplicate.

Common naming mistakes and their symptoms

MistakeWhat happensFix
Underscore in an activity module name (mod/my_activity)Plugin silently ignoredRename the folder to myactivity before first install
Capitals or hyphens in the folder namePlugin silently ignoredLower-case letters, digits and single underscores only
$plugin->component does not match the folderInstall or upgrade stops with a location errorMake the folder and the component agree
Language file named after the folder only (lang/en/acmereports.php for a local plugin)Strings show as [[pluginname]]Use the full component name; only modules use the short form
Tables without the prefixName collisions with other plugins and a schema that breaks the frankenstyle rulesPrefix every table with the component name
Theme named after its parent (theme_boostacme)Confusing names once the parent changesThe frankenstyle docs advise against including the parent theme name

Renaming an installed plugin is not a find-and-replace job. Tables, stored settings in config_plugins, capabilities assigned to roles, scheduled task records and registered web service functions all carry the old name, so a rename is effectively a new plugin plus a data migration. Decide the name before the first install on any shared environment. For directory-specific rules that also affect naming, such as plugins that overlap with Moodle Workplace, see Moodle Workplace plugin development, and for the wider picture, our Moodle guide.

How we can help

We build and review Moodle plugins for organisations that need features core does not offer, from local reports to custom activity modules and admin tools, with names, schemas and capabilities planned before the first install. See our Moodle plugin development service, our wider Moodle services, or contact us with what you want to build.

Frequently asked questions

What is frankenstyle in Moodle?

Frankenstyle is Moodle's naming convention for components: the plugin type prefix, an underscore and the plugin's folder name, for example mod_forum or local_myplugin. Core subsystems use core_ plus the subsystem name, such as core_course.

Can a Moodle plugin name contain an underscore?

For most plugin types, yes, as long as there are no double underscores and the name ends with a letter or digit. Activity modules are the exception: their names may contain only lower-case letters and digits. Core still discourages underscores and numbers in any plugin name.

Why does my new Moodle plugin not appear on the upgrade page?

A common cause is an invalid folder name. Moodle silently ignores plugins whose machine name has capitals, hyphens, double underscores or, for activity modules, any underscore. Also check that $plugin->component in version.php matches the folder.

Why are forum tables not called mod_forum_posts?

Activity modules predate the frankenstyle convention, so their tables, language files and lib.php callbacks use the bare module name. Newer parts of a module, such as its namespace, capabilities and templates, use the full mod_forum name.

Free 30-minute consultation

Not sure where to start? Talk to an LMS engineer.

Tell us what platform you run and what you need. You’ll get honest, practical advice - even if the answer is that you don’t need us.

Sources & references

  1. Frankenstyle component names - Moodle
  2. Plugin types - Moodle
  3. version.php - Moodle
  4. lib/components.json (Moodle 5.3.0) - Moodle
  5. core_component class (Moodle 5.3.0) - Moodle
Add as a preferred source on Google

Add All-in-One LMS as a preferred source to see more of our articles in Google’s Top Stories.

Learn more about this topic with AI

Gemini opens with the prompt copied - paste it into the chat to start.

Keep reading

Before you go - get a free LMS audit

Tell us which LMS you use and what is not working. An engineer replies within one business day.

Choose which optional cookies we may use. You can change this at any time from "Cookie preferences" in the footer. Cookie policy · Privacy policy