| name | joomla6-code-reviewer |
| description | Core Joomla 6 code reviewer skill. Audits extension files (components, modules, plugins, libraries, templates) for compliance with Joomla 6 best practices, native MVC, PSR-4 namespacing, dependency injection, modern PHP, security, and Bootstrap 5 / vanilla ES2020+ frontend standards. Rejects Joomla 3/4 J* classes, FOF, jQuery, and any modification of Joomla core files. |
Joomla 6 Code Reviewer Skill
A specialized review skill that performs comprehensive consistency checking on Joomla 6 extension files (components, modules, plugins, libraries, templates) to ensure full alignment with core Joomla 6 best practices.
When to Use This Skill
Trigger this skill when:
- Reviewing extension files for Joomla 6 compliance
- Auditing code migrated from Joomla 3/4/5 (or FOF) to native Joomla 6 MVC
- Validating PSR-4 namespace conventions
- Verifying security practices (CSRF, SQLi, XSS, input filtering)
- Auditing database query patterns for parameter binding
- Checking
services/provider.php and DI container registrations
- Reviewing plugin event handlers (
SubscriberInterface + typed events)
- Validating XML form definitions and custom field declarations
- Ensuring
WebAssetManager usage for all CSS/JS
- Confirming language string usage and file placement
- Verifying that no Joomla core file is being modified
Hard Rejection List
Flag as CRITICAL on sight:
- Any
J*-prefixed Joomla 3 class: JFactory, JTable, JModel, JController, JView, JHtml, JText, JRoute, JUri, JRequest, JInput, JLog, JFolder, JFile, JLoader::register, etc.
- Any FOF code:
F0FController, F0FModel, F0FTable, F0FViewHtml, F0FPlatform
- jQuery in any form:
$(), jQuery, jquery.min.js, $.ajax(), jQuery UI, jQuery-dependent Bootstrap JS
Factory::getDbo() (legacy) — must use DI / $this->getDatabase()
Factory::getUser() / Factory::getUser($id) — removed in Joomla 6
Joomla\CMS\Filesystem\* — moved to Joomla\Filesystem\* in Joomla 6
- Bootstrap 2/3/4 classes:
pull-left, btn-default, hidden-xs, col-xs-*, etc.
- Any modification to a file inside Joomla core paths (see "Core File Modification Check" below)
Review Categories
0. Core File Modification (run first — CRITICAL)
Extensions must never modify Joomla core files. Flag any change inside:
/libraries/, /api/, /includes/, /cli/, /installation/
- Core components (
com_content, com_users, com_config, com_modules, com_plugins, com_templates, com_categories, com_menus, com_media, com_installer, com_admin, com_login, com_cpanel)
- Core plugins, core modules, core templates (
cassiopeia, atum)
Required alternative: extend Joomla via plugins, event subscribers, service overrides, template overrides (in your own template), or your own component/module/plugin/library.
1. Namespace & Class Structure
- PSR-4 namespace declaration matching the file path on disk
declare(strict_types=1); present at top of every PHP file
\defined('_JEXEC') or die; after declare/namespace
- Vendor segment is the extension's own vendor — never
Joomla
- Use statements grouped (Joomla CMS, Joomla Framework, third-party, project) and alphabetized
final on classes that are not designed for extension
2. MVC Architecture Compliance
- Controllers extend
Joomla\CMS\MVC\Controller\BaseController / FormController / AdminController
- Models extend
ListModel / AdminModel / BaseDatabaseModel
- Views extend
Joomla\CMS\MVC\View\HtmlView (aliased), class name is HtmlView
- Tables extend
Joomla\CMS\Table\Table, take DatabaseDriver in constructor
services/provider.php returns anonymous class implementing ServiceProviderInterface
- Component class implements
ComponentInterface
3. Security Standards
- All output escaped with
$this->escape() / htmlspecialchars()
- All queries use prepared statements with
bind() and ParameterType
$this->checkToken() on every state-changing handler (POST/PUT/DELETE)
- Input filtered with the appropriate
getInt/getCmd/getString/getBool/etc.
- ACL enforced via
$user->authorise() on every controller action
- No
eval(), no unserialize() on untrusted input
- File uploads validated for type, size, and destination
4. Database Operations
$this->getDatabase() in models; DI-injected DatabaseInterface elsewhere — never Factory::getDbo()
- All identifiers wrapped in
quoteName()
- All values bound with
bind(':name', $value, ParameterType::*)
- Table prefix uses the
#__ token, never a hardcoded prefix
- Schema changes shipped via install/update SQL files, not runtime DDL
5. Dependency Injection
services/provider.php registers MVCFactory and ComponentDispatcherFactory with the correct namespace
- Component sets
ComponentInterface::class in container
- Plugins also have a
services/provider.php
- Constructor injection over service location
6. Frontend Standards
- Vanilla JavaScript only (ES2020+) — no jQuery, no
$(), no $.ajax()
fetch() for AJAX, with proper error handling
- All CSS/JS registered via
WebAssetManager (joomla.asset.json) — no raw <script>/<link> injection
- Bootstrap 5 markup and utilities only
- No inline
onclick / onchange / onsubmit handlers
7. Language & Localization
- All UI strings use
Joomla\CMS\Language\Text::_() / Text::sprintf()
- Frontend strings live in
language/en-GB/{element}.ini
- Admin-only strings live in
administrator/.../language/en-GB/{element}.ini
- System strings (menu types, install messages) live in
*.sys.ini
- No hardcoded user-facing text in PHP, XML, or templates
8. Form Handling (XML)
- XML form fields use Joomla 6 native field types
- Boolean yes/no radios use
layout="joomla.form.field.radio.switcher" (not the legacy class="btn-group btn-group-yesno")
- Custom field types declare
addfieldprefix="{Vendor}\\Component\\{ComponentName}\\Administrator\\Field" on <fieldset> or <field> (required for plugin/module forms and subform sources)
- Every
<field> element uses one attribute per line with /> on its own line
- All inputs include
filter and (where applicable) validate
Quick Reference Checklist
File Header
<?php
declare(strict_types=1);
namespace Vendor\Component\Example\Administrator\Controller;
\defined('_JEXEC') or die;
Controller Pattern
use Joomla\CMS\MVC\Controller\FormController;
class ItemController extends FormController
{
protected $text_prefix = 'COM_EXAMPLE_ITEM';
}
use F0FController;
class ItemController extends JController {}
Model Pattern (prepared statements)
use Joomla\Database\ParameterType;
$db = $this->getDatabase();
$query = $db->getQuery(true)
->select($db->quoteName(['id', 'title']))
->from($db->quoteName('#__example_items'))
->where($db->quoteName('state') . ' = :state')
->bind(':state', $state, ParameterType::INTEGER);
$query->where('state = ' . $state);
View Pattern (XSS prevention)
<?php echo $this->escape($item->title); ?>
<?php echo $item->title; ?>
Service Provider
return new class () implements ServiceProviderInterface {
public function register(Container $container): void
{
$container->registerServiceProvider(new MVCFactory('\\Vendor\\Component\\Example'));
$container->registerServiceProvider(new ComponentDispatcherFactory('\\Vendor\\Component\\Example'));
}
};
Plugin Event Handler
final class Plugin extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return ['onContentPrepare' => 'onContentPrepare'];
}
public function onContentPrepare(ContentPrepareEvent $event): void
{
$item = $event->getItem();
}
}
public function onContentPrepare($context, &$article, &$params, $page = 0) { }
Database Access
$db = $this->getDatabase();
$db = Factory::getContainer()->get(DatabaseInterface::class);
$db = Factory::getDbo();
$db = JFactory::getDbo();
User Object (CRITICAL — Factory::getUser() removed in Joomla 6)
$user = Factory::getUser();
$user = Factory::getUser($userId);
$user = $this->getCurrentUser();
$user = Factory::getApplication()->getIdentity();
use Joomla\CMS\User\UserFactoryInterface;
$user = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById((int) $userId);
Filesystem Namespace (moved in Joomla 6)
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Filesystem\Path;
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;
Web Asset Manager
$wa = $this->getDocument()->getWebAssetManager();
$wa->useStyle('com_example.admin')
->useScript('com_example.admin');
HTMLHelper::_('script', 'com_example/admin.js', ...);
echo '<script src="..."></script>';
XML Form Field Formatting
<field
name="enabled"
type="radio"
label="JSTATUS"
default="1"
layout="joomla.form.field.radio.switcher"
>
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
<field name="enabled" type="radio" class="btn-group btn-group-yesno" default="1">
<option value="1">JYES</option>
<option value="0">JNO</option>
</field>
Review Output Format
When reviewing code, output in this format:
## Code Review: [path/to/file]
### Summary
- **Compliance Level**: [PASS ✅ | NEEDS_WORK ⚠️ | FAIL ❌]
- **Critical Issues**: [count]
- **Warnings**: [count]
- **Suggestions**: [count]
### Critical Issues ❌
1. **[Issue Title]**
- Line: [n]
- Current: `[code]`
- Required: `[corrected code]`
- Reason: [explanation, with reference to checklist section]
### Warnings ⚠️
1. **[Warning Title]**
- Line: [n]
- Recommendation: [suggestion]
### Suggestions 💡
1. [Improvement suggestion]
### Passed Checks ✅
- [List of checks that passed]
Integration with Other Skills
This skill works in conjunction with:
joomla6-extensions — extension structure, MVC patterns, manifests, service providers
joomla6-general-concepts — DI, ACL, DB, forms, routing, web assets
joomla6-security — XSS, SQLi, CSRF, input handling
joomla6-component-architect — component architecture and migration blueprints
Reload these skills before flagging or recommending Joomla 6 patterns. Do not infer Joomla 6 behavior from Joomla 3/4/5 memory.
Reference Files
Detailed reference documentation lives in references/:
namespace-patterns.md — PSR-4 conventions for components, modules, plugins, libraries
mvc-checklist.md — controller/model/view/table compliance checklist
security-checklist.md — CSRF, SQLi, XSS, input, ACL, file upload checklist
database-patterns.md — query building, prepared statements, schema conventions
di-patterns.md — service providers, container registration, constructor injection
legacy-migration.md — Joomla 3/4/5 and FOF → Joomla 6 mapping table
Best Practices
- Run the core-modification check first. Any change inside Joomla core paths is an immediate
❌ FAIL.
- Review one file at a time. Focused review catches more than batch passes.
- Verify against the actual database schema. Never recommend a column name without confirming it exists.
- Cross-reference imports. Every
use statement must resolve to a Joomla 6 class, not a removed one.
- Validate form XML. Field names must match model fields and form-loading expectations.
- Test event handlers. Verify the typed
Event subclass matches the subscribed event.
- Mark unverifiable findings explicitly. Use
[UNVERIFIED — confirm before implementation] rather than guessing.
Resources