THE GRUE Get professional WordPress themes

How to Add a New Module Position to a Joomla 3.x Template

Sooner or later every Joomla template runs out of the right slot. The client wants a promo strip between the slideshow and the content, or a trust-badges row above the footer, and the template offers nothing there. You can shoehorn the module into a nearby position and fight the CSS, or you can do the clean thing: add a proper new module position to the template.

The clean thing is easier than its reputation suggests. A module position in Joomla 3.x is just two edits — a declaration in templateDetails.xml and an output statement in index.php — plus a conditional wrapper so the region disappears gracefully when empty, and a few lines of CSS. Twenty minutes, most of it verification.

This tutorial walks through the full job on a worked example: adding a position called promo that renders full width between the header and the main content. Swap in your own name and location; the mechanics are identical anywhere in the layout.

Before you edit anything

Two minutes of preparation saves the awkward restore-from-panic later.

  • Copy the files you will touch. Download templateDetails.xml and index.php from the template folder and keep the originals somewhere safe. If the site matters, do the work on a staging copy first.
  • Check what already exists. Templates often declare positions their demo never used. Map the current layout with the ?tp=1 preview — our tutorial on how to find template module positions in Joomla covers the technique — because the slot you need may already be there under an unglamorous name.
  • Mind template updates. Edits to index.php can be overwritten when the template updates. Note the change in your project docs, and if the template supports a child theme or protected custom files, prefer those. This is exactly the kind of change that belongs in the internal notes we describe in our piece on Joomla template documentation.

Step 1: declare the position in templateDetails.xml

Open templateDetails.xml in the template's root folder and find the positions block — a list of position elements. Add yours to the list:

<positions>
  <position>header</position>
  <position>banner</position>
  <position>promo</position>
  <position>footer</position>
</positions>

The declaration is what makes the name appear in the Position dropdown when editing a module. Naming advice from experience: lowercase, no spaces, and descriptive of location or purpose (promo, above-content, footer-badges). Avoid names that collide with CSS classes the template already uses, and resist cute names you will not remember in a year.

One Joomla 3.x quirk worth knowing: the dropdown reads this XML file directly, so the new name shows up as soon as the file is saved. But a declared position renders nothing by itself — it is a label with no location until step 2.

Step 2: output the position in index.php

Open the template's index.php and find the spot in the markup where the new region belongs. Orient yourself by the existing jdoc:include statements — in our example, we want the region after the header block and before the container that holds the component output. The minimal version is a single line:

<jdoc:include type="modules" name="promo" style="none" />

When Joomla renders the page, it replaces this tag with the output of every published module assigned to promo, in their ordering from the Modules manager. The style attribute picks the module chrome — none outputs the bare module, while xhtml wraps each module in a div with the module title as a heading. Match whatever the template uses for its other content positions so your region inherits consistent styling.

Step 3: wrap it in a countModules conditional

The minimal version works, but it has a flaw: if you wrap the include in layout markup — and you will want to, for width and spacing — that wrapper renders even when no module is published, leaving a strip of empty padded markup on every page. The fix is the template developer's standard idiom: ask Joomla whether the position has any modules before printing the wrapper.

<?php if ($this->countModules('promo')) : ?>
<div id="promo-region">
  <div>
    <jdoc:include type="modules" name="promo" style="none" />
  </div>
</div>
<?php endif; ?>

The countModules method returns how many published, assigned modules the position has on the current page — zero means the whole block is skipped, markup and all. This is exactly how well-built templates make sidebars collapse when empty, and it is why some declared positions never show up in a ?tp=1 preview: nothing is published in them, so their wrapper never prints.

The method also accepts simple expressions, which is handy for multi-column regions that should share a row only when siblings are occupied:

<?php if ($this->countModules('promo or promo-b')) : ?>
  ...row markup for one or both columns...
<?php endif; ?>

Step 4: style the new region

Where the CSS goes matters as much as what it says. If the template loads a user.css or custom.css automatically, put your rules there so template updates cannot erase them; otherwise add them at the end of the main stylesheet and note the edit in your docs. For our full-width promo strip, something like:

#promo-region {
  width: 100%;
  padding: 1.5rem 0;
  background: #f5f7fa;
}

#promo-region > div {
  max-width: 1140px;
  margin: 0 auto;
  padding: 0 15px;
}

Match the inner max-width and gutter padding to the template's existing container so the region aligns with the rest of the page — pull the values from the template's main container class using your browser's dev tools. If the template is built on a grid framework, you can often reuse its container and row classes directly in your wrapper markup instead of writing custom rules at all.

Step 5: assign a module and verify with ?tp=1

Time to see it work. In the administrator, create or edit a module — a custom HTML module is the perfect test payload — and set its Position to promo, which now appears in the dropdown. Publish it, set Menu Assignment to On all pages for the test, and load the front end.

Then verify properly: enable Preview Module Positions in the Templates options and load the site with ?tp=1 appended to the URL. You should see your new region outlined and labeled in place. Check three things while you are there:

  1. The region appears exactly where intended on the homepage, an article page, and a blog layout — templates sometimes use different structural files or conditionals per page type.
  2. Unpublish the test module and reload: the region should vanish completely, with no empty band left behind. That is your countModules wrapper doing its job.
  3. Resize to phone width and confirm the region behaves — full-width strips usually survive untouched, but anything column-based needs a look.

Quick reference: the three files

File What you add What it accomplishes
templateDetails.xml A position element with the new name Makes the position selectable in the module editor
index.php jdoc:include inside a countModules conditional Renders assigned modules; skips markup when empty
user.css / custom.css Rules for the region wrapper Width, spacing, and background for the new area

Troubleshooting the usual suspects

When the new position misbehaves, it is nearly always one of these:

  • The name is not in the Position dropdown. The XML edit did not save, has a typo, or you edited a different template's manifest than the site's active template style.
  • The dropdown shows it but nothing renders. The jdoc:include name does not exactly match the declared name (these are case-sensitive string matches), or the module is unpublished or menu-limited off the page you are testing.
  • It renders on some pages only. Your include sits inside an existing conditional in index.php — check what surrounds your insertion point — or the site assigns a different template style to those menu items.
  • An empty band appears when no module is published. The wrapper markup escaped the countModules conditional; move the whole block inside it.
  • Styling is ignored. Your CSS file loads before the template's main stylesheet or is not loaded at all; confirm the file is referenced in the page source and that your selector specificity holds up.

For deeper reference on template structure, the official Joomla documentation covers the template system in detail, including module chrome styles and the full countModules syntax.

FAQ

Will my new position survive a template update?

The XML declaration and the index.php edit are both at risk: update packages typically replace those files wholesale. Keep a diff or a copy of your changes so you can reapply them in minutes after an update, and record the customization in your project notes. If the template vendor provides a child-theme mechanism or promises certain files are never overwritten, use those paths. The CSS is safe if it lives in a user.css-style file the vendor guarantees to preserve.

Can I add a position without editing index.php?

Not for a genuinely new layout region — the page can only output what some template file prints. What you can do without touching PHP is reuse an existing declared position that already renders where you need it, which is why auditing the current positions first is always worth the ten minutes. Some commercial templates with layout builders let you create regions from the admin interface, but under the hood they are doing the same declaration-plus-output work for you.

Does the position name in the XML have to match the jdoc:include exactly?

The rendering match that matters is between the module's assigned position and the name attribute in the jdoc:include — that comparison is exact and case-sensitive. The XML declaration is what surfaces the name in the dropdown, so all three should agree. Nothing stops a template from outputting a position that was never declared; modules assigned by typing the name manually will render there, but the omission confuses every future maintainer, so declare everything you output.

How many module positions is too many?

Technically Joomla does not care — templates with sixty positions exist. Practically, every position is a promise you make to future maintainers, and unused ones are noise in the dropdown and clutter in the docs. Add positions you have a concrete use for, name them clearly, and prune dead ones from the XML when you are certain nothing references them. A tidy fifteen beats a chaotic fifty.

The bottom line

Adding a module position to a Joomla 3.x template is a declaration in templateDetails.xml, a jdoc:include in index.php, a countModules wrapper so empty regions leave no trace, and a few lines of CSS in an update-safe file. Verify with ?tp=1 across several page types, write the change down, and keep copies of the edited files for the day the template updates. It is honest, low-risk template surgery — and once you have done it, a template that lacks the right slot stops being a limitation and becomes a twenty-minute task. More template tutorials live in our Joomla hub.