The first module
A module is a block the administrator places in a template position. We start with the simplest one: the mod_hello module prints a single greeting line. It shows which files every Joomla 4 and 5 extension is made of.
Module files
In the modules folder of the site create a mod_hello folder with four files:
modules/mod_hello/
├── mod_hello.xml the manifest
├── services/
│ └── provider.php wires the module into Joomla
├── src/
│ └── Dispatcher/
│ └── Dispatcher.php prepares the data
└── tmpl/
└── default.php the layout: HTML markupJoomla has no command that generates files — folders and files are created by hand.
The manifest
The mod_hello.xml file is the one covered in the previous lesson. Two parts of it matter here:
<namespace path="src">My\Module\Hello</namespace>
<files>
<folder module="mod_hello">services</folder>
<folder>src</folder>
<folder>tmpl</folder>
</files>The first sets the namespace of the classes, the second lists the module folders.
The service provider
The provider is the file Joomla starts with when it works with an extension. It tells Joomla where to look for the module classes:
// modules/mod_hello/services/provider.php
defined('_JEXEC') or die;
use Joomla\CMS\Extension\Service\Provider\HelperFactory;
use Joomla\CMS\Extension\Service\Provider\Module;
use Joomla\CMS\Extension\Service\Provider\ModuleDispatcherFactory;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
return new class () implements ServiceProviderInterface {
public function register(Container $container): void
{
$container->registerServiceProvider(new ModuleDispatcherFactory('\\My\\Module\\Hello'));
$container->registerServiceProvider(new HelperFactory('\\My\\Module\\Hello\\Site\\Helper'));
$container->registerServiceProvider(new Module());
}
};The file is almost identical in every module — only the namespace changes. The HelperFactory line is needed in the next lesson.
The dispatcher
The dispatcher is a class that prepares data for the layout:
// modules/mod_hello/src/Dispatcher/Dispatcher.php
namespace My\Module\Hello\Site\Dispatcher;
defined('_JEXEC') or die;
use Joomla\CMS\Dispatcher\AbstractModuleDispatcher;
class Dispatcher extends AbstractModuleDispatcher
{
protected function getLayoutData(): array
{
$data = parent::getLayoutData();
$data['greeting'] = 'Hello!';
return $data;
}
}The getLayoutData() method returns an array. Joomla adds the word Site to the namespace from the manifest by itself — because the module is meant for the site.
The layout
<?php
// modules/mod_hello/tmpl/default.php
defined('_JEXEC') or die;
?>
<p class="mod-hello"><?php echo htmlspecialchars($greeting, ENT_QUOTES, 'UTF-8'); ?></p>Every key of the dispatcher array becomes a variable in the layout: $data['greeting'] turned into $greeting.
The defined('_JEXEC') line
The _JEXEC constant is defined only when the code runs through Joomla. If the file is opened directly by its address, it stops at once. This line goes at the top of every PHP file of an extension.
Installing and seeing the result
- System → Install → Discover → Discover → tick
mod_hello→ Install. - Content → Site Modules → New → choose
mod_hello. - Set the title "Greeting", the position
sidebar-right, the status Published. - On the Menu Assignment tab choose On all pages and save.
Open the site: the right column now has a "Greeting" block with the line "Hello!".
Common mistake
The namespace must match in three places: the namespace tag of the manifest, the provider and the class itself. With a typo the module is not rendered or shows a "class not found" error. Compare the three lines and remember: on a Linux server the letter case of folder names such as src/Dispatcher matters.