Joomla Modules and Positions

This content was generated with the assistance of AI and should be verified against the official Joomla documentation before being relied on in production.

This sub-section’s Joomla bibliography lists the reference material consulted while preparing these pages.

A module is the small block of output that Joomla draws around the main component on a page: a menu, a search box, a login form, a list of latest articles, a block of custom HTML. Modules are what turn one component output into a finished page layout, and they are the part of a Joomla site that site builders touch most often after articles and menus. This page explains how a module is selected for a request, how template positions decide where it appears, how the menu assignment, access, language and publishing settings filter it, how a module style wraps it in markup, which module types ship in core, and the module versioning and multilingual associations introduced in Joomla 6.1. It was checked against the official documentation and the 6.2 source tree on 2026-10-30. The behaviour described is that of Joomla 6.2 (current, requiring PHP 8.3 or newer); where Joomla 5.4 (security fixes only) differs, the text says so. Joomla 4.x and 3.x are end of life.

The examples belong to the Tallpine Hiking Club, the fictitious mountain club used across this sub-section. Its site uses the child template cassiopeia_tallpine (see Child templates) and needs a main menu, a trail-conditions notice for members, a breadcrumb trail, a language switcher for English and German, a search box and a banner for partner shops. Writing your own module is covered in Module development; this page is about using and placing modules.

What a module is, and who works with it

Technically a module is an extension of type module (see Extension types, manifests and packaging) whose element name starts with mod_. The extension supplies code and a manifest. An instance of the module, which is what you create in the Administrator, is a row in the #__modules table holding a title, a position, a few state fields (published, access, language, publishing dates), the module’s parameters as JSON, and, for the Custom module, its HTML content. One extension can have many instances, each with its own title, parameters and position.

Several roles work with modules:

  • Editors and site builders create instances in Content → Site Modules, choose a position and a menu assignment, and reorder them.

  • Administrators manage System → Administrator Modules, the modules of the back end (dashboard icons, the user menu, the toolbar), and decide who may edit modules.

  • Themers declare positions in templateDetails.xml, place them in index.php and write module styles.

  • Developers write module extensions, and the Dispatcher and Helper pattern is described in Module development.

Site modules and administrator modules

Joomla keeps two sets of modules, selected by the client_id column of the module row. Site modules (client_id 0) render on the public site, in the positions of the active site template. Administrator modules (client_id 1) render in the back end, in the positions of the active administrator template, which is Atum by default (see The Administrator template Atum).

Aspect Site modules Administrator modules

Menu in the Administrator

Content → Site Modules

System → Administrator Modules

Template that declares positions

The site template, for example Cassiopeia

The administrator template, by default Atum

Typical positions

sidebar-right, menu, footer, breadcrumbs

cpanel, icon, status, toolbar, menu

Menu assignment tab

Present, because the site renders per menu item

Absent

Associations tab (Joomla 6.1)

Present when multilingual associations are enabled

Absent

Module types

Menu, Custom, Articles, Breadcrumbs, Login, Smart Search and more

Custom, Latest Actions, Logged-in Users, Quick Icons, Privacy dashboard and more

The module edit form in the 6.2 source shows the Menu Assignment tab only for site modules, and the Associations tab only when associations are enabled for a site module. Everything else on this page, positions, styles, access, language and publishing, applies to both sets unless the text says otherwise.

How a module reaches the page

A module appears on a page only when a template asks for its position. The template contains one <jdoc:include type="modules" name="sidebar-right" style="card" /> element per position. When the document is rendered, Joomla replaces that element with the output of every module that passes all the filters, in order.

flowchart TD R[Request for a page] --> T[Template index.php] T --> J["jdoc:include type=modules name=sidebar-right style=card"] J --> L[ModuleHelper loads published module rows] L --> F1{Module extension enabled?} F1 -- no --> X[Skipped] F1 -- yes --> F2{Published and inside publish dates?} F2 -- no --> X F2 -- yes --> F3{Access level matches the user?} F3 -- no --> X F3 -- yes --> F4{Assigned to this menu item?} F4 -- no --> X F4 -- yes --> F5{Language matches the site language?} F5 -- no --> X F5 -- yes --> M[Module dispatcher renders the content] M --> C[Module style wraps the content] C --> O[HTML in the position]

The filtering happens in ModuleHelper::getModuleList() in libraries/src/Helper/ModuleHelper.php. In the 6.2 source a single query joins #__modules with #__modules_menu and #__extensions and keeps the rows where the module is published, its extension is enabled, its client matches the current application, its access level is one of the user’s authorised view levels, the current time is inside its publishing window, and the menu assignment matches the current Itemid. The result is cached in the com_modules cache group under a key built from the user’s view levels, the client, the menu item and, on a multilingual site, the language tag. The rows are ordered by position and then by the ordering column. Because that list is cached, a change to a module is normally visible at once (saving a module clears the group), while a change made directly in the database may need the cache cleared in System → Clear Cache.

Two consequences matter in daily work:

  • A module whose extension is disabled in System → Manage → Extensions disappears from every position, even though its instance still shows as published.

  • The filters combine with AND. A module set to "On all pages" but with the access level Registered is still hidden from visitors who are not logged in.

Positions

A position is a named slot in a template. It is only a string: nothing is registered in a table, and a module row simply stores the position name in its position column. Several modules may share one position and are drawn in their Ordering sequence. A module whose position is empty is not drawn. A module placed in a position that the active template does not output is not drawn either, which is the usual reason that "the module is published but I cannot see it" after a template change.

How a template declares positions

A template declares positions in two places that must agree:

  1. In templateDetails.xml, inside <positions>, one <position> element per name. This list feeds the position drop-down in the module editor and the Preview mode. It does not by itself draw anything.

  2. In the template’s index.php (or component.php, error.php), one jdoc:include element per position. This is what actually draws the modules.

Cassiopeia in the 6.2 source declares eighteen positions: topbar, below-top, menu, search, banner, top-a, top-b, main-top, main-bottom, breadcrumbs, sidebar-left, sidebar-right, bottom-a, bottom-b, footer, debug, error-403 and error-404. The last two are used directly by the template’s error.php and are listed in the manifest only so that they appear in the position list. The User Guide mentions sixteen positions in its Cassiopeia description; the two error positions account for the difference.

<!-- templates/cassiopeia_tallpine/templateDetails.xml (excerpt) -->
<extension type="template" client="site" method="upgrade">
    <name>cassiopeia_tallpine</name>
    <version>1.0.0</version>
    <inheritable>0</inheritable>
    <parent>cassiopeia</parent>
    <positions>
        <!-- the module editor reads only this manifest, so list the parent's positions here too -->
        <position>trail-conditions</position>
        <position>partner-strip</position>
    </positions>
</extension>

A child template does not inherit the parent’s position list at run time. The module editor reads the positions from the templateDetails.xml of the active template only, so the child’s manifest must list every position it wants offered, including the parent’s (the Templates manager copies them there when it creates the child). The Tallpine child adds trail-conditions and partner-strip to that list. They only show up in the editor’s drop-down once the template’s index.php outputs them, or, for positions that are not drawn directly, once they are listed in templateDetails.xml. The child-template mechanics, including how index.php is overridden, are covered in Child templates.

Placing a position in index.php

Cassiopeia wraps each jdoc:include in a countModules test so that an empty position produces no wrapper markup and, on the layout grid, no empty column. A position is declared and used like this in a custom layout:

<?php
// templates/cassiopeia_tallpine/index.php (excerpt)
defined('_JEXEC') or die;
?>
<?php if ($this->countModules('trail-conditions', true)) : ?>
    <aside class="container-trail-conditions" aria-label="Trail conditions">
        <jdoc:include type="modules" name="trail-conditions" style="card" />
    </aside>
<?php endif; ?>

<main>
    <jdoc:include type="modules" name="breadcrumbs" style="none" />
    <jdoc:include type="message" />
    <jdoc:include type="component" />
</main>

$this->countModules('trail-conditions', true) counts the modules that would render in that position. The second argument asks for modules that produce non-empty content; a module whose dispatcher outputs nothing then does not make the wrapper appear. The style attribute names the default module style for every module in the position (see Module styles (chrome)). A position may also be written in a condition such as countModules('sidebar-left + sidebar-right') to count several at once.

The jdoc:include type="modules" element accepts name (the position) and style. Other type values include component, message, metas, styles, scripts and module; the last renders one module by name. For asset loading in module and template code see Web Asset Manager.

Cassiopeia’s layout

Cassiopeia is a Bootstrap 5 grid. Its positions group into a header area (topbar, below-top, menu, search, banner), a row above the content (top-a, top-b), a three-column body (sidebar-left, the component with breadcrumbs, main-top and main-bottom around it, sidebar-right), a row below the content (bottom-a, bottom-b), the footer, and a debug position for the debug module. The default style differs by position: topbar, below-top, menu, search, banner, breadcrumbs, footer and debug use style="none", while the content and sidebar positions use style="card". That is why a Custom module in sidebar-right appears in a bordered card and the same module in footer appears bare.

flowchart TB subgraph Header TB[topbar] --- BT[below-top] BR[brand] --- ME[menu] --- SE[search] BA[banner] end subgraph Above content TA[top-a] --- TBB[top-b] end subgraph Body SL[sidebar-left] --- MAIN subgraph MAIN[Main column] BC[breadcrumbs] --> MT[main-top] --> CO[component output] --> MB[main-bottom] end MAIN --- SR[sidebar-right] end subgraph Below content BA1[bottom-a] --- BB1[bottom-b] end FO[footer] DB[debug] Header --> Above Above --> Body Body --> Below Below --> FO FO --> DB

The administrator template Atum declares the positions bottom, debug, menu, sidebar, status, title, top and toolbar, and lists cpanel, icon, login and customtop as positions that components use directly. The dashboard is built from cpanel and icon modules, which is why moving a Quick Icons module to another administrator position takes its icons off the Home Dashboard.

Showing every position: Preview Module Positions

To see where a template draws its positions, even the empty ones, enable the preview switch:

  1. In the Administrator open System → Site Templates (or Site Template Styles) and click Options in the toolbar.

  2. Set Preview Module Positions to Enabled, then Save & Close.

  3. Add ?tp=1 to the site URL, or &tp=1 if the URL already has a query string, for example https://tallpine.example/?tp=1.

The setting is the template_positions_display parameter of the com_templates component, and its default is Disabled. With the switch on and tp=1 in the request, ModuleHelper::getModules() prepends a dummy module to every position that has no real module, with the position name as its title and content, and renderModule() adds the outline style to the style of every module. The result is a page in which each position is outlined and labelled with its name and the style in use. Positions that exist in templateDetails.xml but are never output by index.php still do not show.

Two cautions come from how the switch works. Because it is a global option, any visitor can add ?tp=1 and see the layout of the site while it is enabled, so turn it off on production sites, as the User Guide recommends. And the outline style wraps real modules too, so a page previewed with tp=1 is not a faithful rendering of the final markup.

Module assignment to menu items

A site module is shown only on the pages whose menu item it is assigned to. The Menu Assignment tab offers four choices:

Option Effect

On all pages

The module is shown on every page, including pages without a menu item. This is the default for a new module.

No pages

The module is saved but never shown. Use it to park a module without unpublishing it.

Only on the pages selected

The module is shown only on the checked menu items.

On all pages except those selected

The module is shown everywhere, except on the checked menu items.

The last two options reveal a Menu Selection tree that lists every menu and its items. The Expand the Menu Subtrees button collapses or opens the tree; a menu or a branch can be checked as a whole. Hiding the breadcrumb trail on the home page is a classic use: choose On all pages except those selected, collapse the tree, expand Main Menu and check Home.

Internally the assignment is stored in #__modules_menu, one row per module and menu item. A menuid of 0 means "all pages", a positive value is a selected menu item, and a negative value is an excluded one (the item’s id with a minus sign). "No pages" stores no row, so the join in the query matches nothing. cleanModuleList() then drops any module that has a row whose negated value equals the current Itemid, which is how "all pages except" works.

-- Read-only: which pages show module 42 ("Trail conditions" notice)?
-- Replace #__ with the configured table prefix.
SELECT mm.menuid, m.title
FROM #__modules AS m
LEFT JOIN #__modules_menu AS mm ON mm.moduleid = m.id
WHERE m.id = 42;

Pitfalls of menu assignment:

  • The assignment is by menu item, not by URL or article. Two menu items pointing at the same category are two different pages for module purposes, and the module query uses the Itemid of the request. A page that no menu item targets shows only the modules assigned to all pages (and the ones using exclusions for other items).

  • A menu item created after the module was saved is not in an "Only on the pages selected" list until someone checks it, while "On all pages" and "On all pages except those selected" cover it automatically.

  • On a multilingual site a menu item exists per language. A module assigned only to the English menu items does not appear on the German pages, even with its language set to "All"; assign the German items too, or use "On all pages".

Module fields: title, state, access, language and publishing

The Module tab of every site module has a content column and a sidebar with the settings common to all types. They are defined once in administrator/components/com_modules/forms/module.xml:

Field Meaning

Title

Required. Shown as the module heading when Show Title is on, and used as the accessible name of the region when the module tag is not a div.

Show Title

Show (the default) or Hide. A hidden title is still used for the aria-label of tagged modules.

Position

The position name. The field offers the positions of every installed template, and also accepts a typed value, which is how a position of a template not yet installed can be pre-filled. Position names are stored in lower case, so use lower case in templates too.

Status

Published, Unpublished or Trashed.

Start Publishing and Finish Publishing

Optional date and time (stored in UTC and shown in the user’s time zone). Outside this window the module is not loaded. Joomla does not unpublish the row at the end of the window; the query simply excludes it.

Access

One of the site’s access levels: Public, Guest, Registered, Special or a custom level such as Trail Wardens. Only users whose groups map to that level see the module.

Ordering

The sequence inside the position. The list is linked to the position field and shows the other modules of the position.

Language

All (stored as *) or a content language. Honoured only when the Language Filter system plugin is enabled.

Note

A free text of up to 255 characters shown in the list. Use it to record why a module exists.

Version Note

Up to 255 characters, stored with a saved version (see Module versioning (Joomla 6.1)).

Ordering

Open Content → Site Modules, sort the list by the Ordering column (the column heading icon), then drag the handle of a row to move it up or down inside its position. Dragging works within one position at a time. The same ordering applies on every page where the module is shown. Filter the list by position first, otherwise the drag order of unrelated modules is meaningless.

Access

The access level is the visibility gate for visitors, and the Permissions tab is a separate gate for editors.

  • Access decides who sees the module on the site. The check uses the user’s authorised view levels (getAuthorisedViewLevels()), so a module with level Trail Wardens is shown to members of the custom Trail Warden group and to nobody else. The Tallpine trail-conditions notice for members uses this.

  • Permissions decides who may create, edit, change the state of or delete modules. A group needs Create, Edit and Edit State on the Modules component. The tab appears only for users who have Configure ACL & Options (core.admin). Roles, groups and access levels are explained in Users, groups, access levels and ACL.

A module hidden by its access level is still sent to the caching layer under a key that contains the user’s view levels, so a cached page for visitors does not leak a module meant for members. The corollary is that page caching and the Progressive caching option multiply cache entries on sites with many access levels (see Caching and performance). The access level is a presentation filter, not a security boundary: a Registered module that prints private data to a hidden element still sends that data to anyone who can load the page. Put sensitive content in a component whose own ACL decides.

Language

The Language field has an effect only on a multilingual site, meaning when the Language Filter plugin is enabled (see Multilingual sites). With the plugin on, getModuleList() keeps modules whose language is the current language or *. With the plugin off, the field is stored but ignored, so a German module still shows on an English-only site. In the back end, administrator-module language filtering needs the corresponding administrator multilingual setting.

For Tallpine, the site has one Main Menu module per language, each set to its language and its own menu, and a single Language Switcher module set to All.

Publishing states and dates

The states are Published, Unpublished and Trashed. Trashed modules are kept until emptied from the Trashed filter. The start and finish dates make time-limited banners easy: the Tallpine "Winter hut booking opens" notice has a start date and a finish date and needs no cleanup afterwards. Pitfalls are the time zone (the dates are converted from the user’s time zone to UTC on save) and caching: the module list is cached, so the change appears when the cache entry expires or is cleared, not at the exact second.

Module styles (chrome)

A module style, historically called chrome, is the wrapper markup around a module’s output. The module itself produces the content; the style adds the heading, the container and the CSS classes. Choosing a style changes the look of a module without touching the module.

Styles are layout files in a chromes folder:

  • the system styles live in layouts/chromes/ (for example none.php, html5.php, table.php, outline.php);

  • a template can add or replace styles in templates/<name>/html/layouts/chromes/ (Cassiopeia ships card.php and noCard.php there).

The style used for a module is chosen in this order, as the 6.2 renderModule() does it: the module’s own Module Style setting on the Advanced tab, when it is not empty; otherwise the style attribute of the jdoc:include in the template; otherwise none. When Preview Module Positions is active, outline is appended. A space-separated list such as style="card outline" applies the layouts in sequence, each wrapping the previous one.

Style What it outputs

none

Only the module content. No wrapper and no heading.

html5

A div (or the configured module tag) with the classes moduletable and the module class suffix, and the heading in the configured header tag when the title is shown.

table

Wraps the module in a table; the heading becomes a table header cell. A legacy style kept for old markup.

outline

A labelled box showing the position and style names, used by the position preview.

card

Cassiopeia style. A Bootstrap card: the module tag carries the classes card and the position name, the heading gets card-header (or card-title inside card-body when the header class is card-title), and the content sits in a card-body div.

noCard

Cassiopeia style. Same classes as card but without the Bootstrap card classes, for a plain container.

The Advanced tab

The Advanced tab of every module is defined in administrator/components/com_modules/forms/advanced.xml and carries the fields that control the wrapper:

  • Module Tag: the HTML element, div by default, or section, aside, nav, address, article, footer, header and so on. When the tag is not a div, the style adds aria-labelledby (title shown) or aria-label (title hidden), which helps screen reader users move between landmarks.

  • Bootstrap Size: a value from 0 to 12 for the grid column width, used by templates that read it.

  • Header Tag: h3 by default, from h1 to h6 and p. Choose the heading level that fits the page outline.

  • Header Class: CSS classes for the heading. The value is validated as CSS identifiers.

  • Module Style: a list of the styles available in the active template and the system, written as <Template>-<style>, for example Cassiopeia-noCard or System-html5. The value is split at the first dash: the first part names the template whose html/layouts folder holds the style (System means the system layouts), the second the style.

Most modules also offer Module Class (moduleclass_sfx) on their own advanced tab. It is appended to the container’s class attribute, so a module class of text-center centres its content, and a tallpine-notice class can be styled in user.css or in the child template’s own stylesheet. A leading space in the old suffix convention is no longer needed in Cassiopeia, but one does no harm.

Writing a style for the child template

The Tallpine child template adds a style that renders members' notices as a Bootstrap alert. A file in templates/cassiopeia_tallpine/html/layouts/chromes/ is found automatically.

<?php
// templates/cassiopeia_tallpine/html/layouts/chromes/notice.php
defined('_JEXEC') or die;

use Joomla\CMS\Language\Text;

$module  = $displayData['module'];
$params  = $displayData['params'];

if ($module->content === null || $module->content === '') {
    return;
}

$moduleClass = htmlspecialchars($params->get('moduleclass_sfx', ''), ENT_QUOTES, 'UTF-8');
?>
<div class="alert alert-info tallpine-notice <?php echo $moduleClass; ?>" role="note">
    <?php if ($module->showtitle) : ?>
        <h3 class="alert-heading"><?php echo htmlspecialchars($module->title, ENT_QUOTES, 'UTF-8'); ?></h3>
    <?php endif; ?>
    <?php echo $module->content; ?>
</div>

Source: Joomla Manual: Web Asset Manager (assets for chromes follow the same registry) and Joomla CMS source: the Cassiopeia card chrome

The file name is the style name, so notice.php becomes a Cassiopeia_tallpine-notice option on the module’s Advanced tab and style="notice" in index.php. Return early on empty content as the core styles do, escape every value the chrome prints, and never print $module->content through an extra filter that strips markup the module meant to emit. More on layouts, overrides and chromes is in Layouts and module chromes and Template overrides and alternative layouts.

Place the module in the template with:

<jdoc:include type="modules" name="trail-conditions" style="notice" />

The core module types

Content → Site Modules → New lists the module types installed. The User Guide counts twenty-four types in core: Articles (Archived, Categories, Category, Latest, Most Read, Newsflash, Related), Banners, Breadcrumbs, Custom, Feed Display, Footer, Language Switcher, Latest Users, Login, Menu, Random Image, Smart Search, Statistics, Syndication Feeds, Tags (Popular, Similar), Who’s Online and Wrapper. The 6.2 source tree also contains the newer unified Articles module (mod_articles, version 5.2.0 in the manifest), which sits beside the older article modules. The sections below cover the types Tallpine uses most.

Menu (mod_menu)

Draws a menu in a position. Its basic parameters are Select Menu (menutype), Base Item (base), Start Level (startLevel), End Level (endLevel) and Show Sub-menu Items (showAllChildren). Start and end level slice the tree so that a module in sidebar-left can show only the children of the current section. The advanced tab adds the menu tag ID, menu class, layout and caching. The menu items themselves are managed in Menus, see Menus and menu items. In Cassiopeia the main menu module goes in menu (style none); the layout draws a Bootstrap navbar, so the choice of position and style matters.

Custom (mod_custom)

A module whose content is HTML written in the editor. The basic fields are Prepare Content (prepare_content), which runs the content plugins on the text so that tags such as {loadmoduleid 7} and email cloaking work, and Background Image (backgroundimage). Use it for notices, a footer text, an opening banner or a block of links. Because the content is stored in the module row, it is part of the version history in 6.1 (see Module versioning (Joomla 6.1)). The editor filters markup according to the text filters set in Global Configuration, so a script tag typed by a user without the right filter is removed on save.

Articles (mod_articles and the article modules)

Lists articles from a category selection. The unified module has modes, a count, category filtering, child category handling, include and exclude lists, layouts (list or columns), display switches for title, author, category, date, hits, tags and intro text, and filters for featured, archived and unpublished articles. The older modules (Latest, Most Read, Archived, Newsflash, Categories, Category) remain in the 6.2 tree. Tallpine uses the Articles module in sidebar-right to list the three most recent trail reports from Trails → Alpine.

Breadcrumbs (mod_breadcrumbs)

Shows the trail from the home page to the current page. Parameters: Show 'You are here' (showHere), Show Home (showHome), Home text (homeText) and Show Last (showLast). In Cassiopeia it belongs in breadcrumbs. The trail is built from the menu structure and the component’s pathway, so a component that does not add pathway items yields a short trail.

Login (mod_login)

Draws the login form with the remember-me option, and for a logged-in user a greeting and a logout button. It supports Login Redirection, Logout Redirection, a pre- and post-login text and the option to display the form with links to registration and password reset. The form posts to the user component, so Multi-Factor Authentication (see Security hardening, MFA and passkeys) and the login plugins apply. A login module should be shown over HTTPS only (see Web server, reverse proxy and HTTPS).

Language Switcher (mod_languages)

Shows links, flags or a drop-down to switch content language, built from the content languages and the associations of the page. It needs the Language Filter plugin, content languages and, to switch to the translation of the same article, associations between items. See Multilingual sites.

Smart Search (mod_finder)

A search box for the Smart Search component. It can show a search button, an autocompleter and an advanced-search link and target a chosen menu item or search filter. The index it queries is built by the Smart Search indexer, see Smart Search. A page without a Smart Search menu item still works, because the module supplies the target Itemid.

Banners (mod_banners)

Shows banners managed by the Banners component, by client, category and tag, with a count, ordering and a header and footer text. The Tallpine partner strip uses it in partner-strip. The component is described in Contacts, banners and news feeds.

Popular Tags lists the most used tags, with a time frame, a maximum count and optional counts. Similar Tags lists items that share tags with the current item. Tallpine shows family-friendly and dog-friendly this way. See Categories and tags.

Other types worth knowing

  • Wrapper embeds an external page in an iframe. Treat it with the usual iframe security precautions (the target must allow framing).

  • Syndication Feeds gives a feed link for the current page; Feed Display reads an external RSS or Atom feed.

  • Random Image shows an image from a folder, with the width and height fields leaving the aspect ratio when empty.

  • Footer, Statistics, Latest Users and Who’s Online are simple information modules.

Loading modules inside articles

Modules normally render in positions, but three tags of the Content - Load Modules plugin insert a module into the text of an article, a Custom module or any content that runs the content plugins. The plugin must be enabled, otherwise the tags are shown as plain text.

Tag Effect

{loadposition position,style}

Renders every module in the named position at that spot. The style is optional. Position names should be lower case.

{loadmodule type,title,style}

Renders the first module of the given type (login, languages) or, with a title, a particular instance.

{loadmoduleid 42}

Renders the module with the numeric id. No style argument.

The Module editor button (the Button - Module plugin) inserts these tags from a dialog. A module used this way usually has "No pages" as its menu assignment and a position with no template output (a made-up one is fine), so it renders only where the tag is placed. The module’s access level, publishing dates and language still apply. The plugin’s default style is none; the plugin options set it.

Pitfalls: a tag inside a Custom module requires Prepare Content on; a module included in itself loops, so never put {loadmoduleid 42} inside module 42; and the tags are not processed in the API application, so headless clients read the raw tag. A style given in the tag follows the same rules as the Module Style field.

Module versioning (Joomla 6.1)

Joomla has long kept a version history for articles. Joomla 6.1 extends the same history to modules; the release announcement lists it as "Smarter Modules with Versioning and Multilingual Associations". Each save of a module can store a snapshot in the content history, and a Versions button in the module editor toolbar opens the list, where a version can be previewed, compared, restored or protected from deletion with Keep On/Off.

History is off by default for modules. It is controlled in Content → Site Modules → Options (the com_modules options), which in the 6.2 source offer Enable Versions (save_history, default No) and Maximum Versions (history_limit). The edit form also has a Version Note field (version_note, up to 255 characters) so that an editor can describe a change. The module model implements VersionableModelInterface with VersionableModelTrait, the same contract the article model uses.

<!-- administrator/components/com_modules/config.xml (excerpt, 6.2) -->
<field name="save_history" type="radio" label="JGLOBAL_SAVE_HISTORY_OPTIONS_LABEL"
       layout="joomla.form.field.radio.switcher" default="0">
    <option value="0">JNO</option>
    <option value="1">JYES</option>
</field>
<field name="history_limit" type="number" label="JGLOBAL_HISTORY_LIMIT_OPTIONS_LABEL"
       filter="integer" validate="number" min="0" />

What this changes in practice:

  • Before 6.1 a mistaken edit of a Custom module or a menu module parameter had no undo apart from a database backup. With versions on, the Tallpine editors can restore the previous "Trail conditions" notice in one click.

  • The history stores the module’s form data, including the parameters. It is subject to the permissions of the Modules component and to the Maximum Versions limit, which prunes the oldest unprotected versions.

  • A restore creates a new current state; it does not rewrite history.

  • A site upgraded from 6.0 or 5.4 keeps Enable Versions off until someone turns it on, because the option default is No.

  • On Joomla 5.4 and earlier modules have no version history at all, so a team that relies on it needs 6.1 or newer on every environment that edits modules.

Staged content, for example module wording drafted by an author and published by an editor, is better served by Workflows, which cover articles; module versions record changes but do not add an approval step.

Multilingual associations for modules (Joomla 6.1)

On a multilingual site, articles, categories, menu items and contacts can be associated with their translations so that the Language Switcher sends a visitor to the equivalent page. Joomla 6.1 adds the same association to module instances: a German module can be linked to its English counterpart.

The association appears as an Associations tab in the editor of a site module. In the 6.2 source the tab is shown when Associations::isEnabled() is true and the module is a site module, and the model uses the association context com_modules.item and the table #__modules. The prerequisites are the same as for other items:

  1. The Language Filter system plugin is enabled, and the site has content languages (English and German for Tallpine).

  2. The Language Filter plugin option Item Associations is Yes.

  3. The module has a specific language (not All), because an association links items of different languages.

Tallpine example
  Module "Winter hut notice"      language en-GB   position trail-conditions
  Module "Winterhuetten-Hinweis"  language de-DE   position trail-conditions
  Association: both modules linked in the Associations tab

Associations help editors see which translation a module has and jump between them, and a site’s own code or template can read the association table through the associations helper. They do not change which module is shown: module selection still uses the module’s own language and its menu assignment, as described above. In particular, an associated pair is not "one module with two translations"; each language still needs its own menu assignment and, for a Menu module, its own menu. The Language Switcher’s page-level links come from the page’s items, not from module associations. The wider setup of languages, language switchers and associations for content is in Multilingual sites, and language strings of a module are explained in Language files and internationalisation.

Caching of modules

Each module can cache its own output. Most core modules offer Caching (use global or no caching) and Cache Time on the Advanced tab; the cache mode is declared in the module’s XML (static, itemid, safeuri or id). A caching mode of static stores one entry for every page with the same module parameters, which is right for a footer and wrong for a module that varies by user or page. The module list query is cached separately, as explained above. Details, the conservative and progressive page caches and Redis are in Caching and performance.

Practical walkthrough: the Tallpine trail-conditions notice

  1. Open Content → Site Modules → New and choose Custom.

  2. Title it "Trail conditions", paste the text, set Position to trail-conditions, Access to Trail Wardens, and Language to English (en-GB).

  3. On Menu Assignment choose Only on the pages selected and tick the English Trails branch.

  4. On Advanced choose Module Style Cassiopeia_tallpine-notice and Module Tag aside.

  5. Optionally set Start Publishing to the start of the season.

  6. Save, then reload the English trails page as a Trail Warden. Reload as a visitor: the module is hidden. Add ?tp=1 (with the preview option on) if the position does not show at all.

  7. Duplicate the module with Save as Copy, switch the copy’s language to German, translate it and assign the German menu items. On 6.1 and newer, link the two in the Associations tab.

Common errors and pitfalls

Symptom Likely cause and fix

The module is published but not visible

Check in this order: extension enabled, module published and inside its dates, access level, menu assignment, language, and that the template outputs the position (use ?tp=1).

The module appears in the wrong place after a template change

The position name is not output by the new template. Move the module to a position that exists.

Position drop-down lacks a new position

It is not listed in templateDetails.xml. Add it and, for a child template, make sure the child’s manifest is the one in use.

The module is visible on pages where it should be hidden

Another instance with a different assignment, a cached list, or "On all pages" on a duplicate. Filter the module list by position.

{loadposition} shows as text

The Content - Load Modules plugin is disabled, or the text is not run through content plugins (a Custom module without Prepare Content).

?tp=1 does nothing

Preview Module Positions is still Disabled in the template options.

The language switcher shows no flags or links

The Language Filter plugin or the content languages are not set; see the multilingual page.

Module is shown to the wrong visitors

The access level, not the menu assignment, controls visibility. A Public module is for everyone.

A module has an empty card

The module returns empty output but the style still draws the card; use countModules(..., true) and return early in custom chromes.

Security notes

  • Treat module HTML like article HTML: the Custom module stores whatever the text filter lets through. Keep the filter for authors strict, and give Super Users alone the "No filtering" group.

  • Do not rely on access levels for secrecy; they hide the module from the page for other users but the content still lives in the database and in any cache you share.

  • Give the Create/Edit permissions of modules only to site builders. A user who can edit a Custom module can put a form, an iframe or a link anywhere the template shows that position.

  • Disable Preview Module Positions on production, and keep the debug position output behind the debug setting.

  • Modules in sidebar or status positions of the administrator template run with the viewer’s permissions; third-party administrator modules should check ACL before showing data. See Security in extensions.

Version notes

Version Change

4.0

Cassiopeia and Atum replace Protostar and Isis, with the position names listed above and the Cassiopeia module styles card and noCard.

4.1

Child templates (the child manifest lists every position it offers).

5.0

ES5 assets removed; modules register their assets through the Web Asset Manager.

5.2

The unified Articles module (mod_articles) appears in the source tree.

6.0

Legacy J* aliases, such as JModuleHelper, are only available through the "Behaviour - Backward Compatibility 6" plugin; use Joomla\CMS\Helper\ModuleHelper.

6.1

Module versioning and multilingual associations for modules.

6.2

Current stable release.

The dates and support windows of each release are in Versions, release cycle and support.

Corrections to older books and tutorials

Joomla! 4 Masterclass (2023) describes module positions and the template position preview with Joomla 4 screens, and older tutorials still talk about positions of Protostar, such as position-7. Those names do not exist in Cassiopeia or Atum; use the positions listed above. The same book and older tutorials describe child templates as a brand-new feature (they have been standard since 4.1, and Joomla 6.0 ships cassiopeia_extended). Neither book treats module versions and module associations because they arrived in 6.1. Pre-4.0 advice such as <jdoc:include type="modules" name="left" style="xhtml" /> uses the removed xhtml style; use html5, none or the Cassiopeia styles. The JModuleHelper class name in Developing Extensions for Joomla! 5 (2023) is the legacy alias discussed in Where older books and tutorials are outdated. Where a book and the current User Guide disagree, follow the User Guide.

The User Guide’s module styles page mentions an "inherited" module style in one paragraph but does not list it among the style options; in the 6.2 source an empty Module Style is what inherits the style from the template’s jdoc:include.