Imported from mortezahonar/ClaudeForJoomla (
.claude/skills/joomla6-code-reviewer/SKILL.md). Install upstream withnpx skills add mortezahonar/ClaudeForJoomla --skill joomla6-code-reviewer. Copyright stays with the author.
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.phpand DI container registrations - Reviewing plugin event handlers (
SubscriberInterface+ typed events) - Validating XML form definitions and custom field declarations
- Ensuring
WebAssetManagerusage 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 6Joomla\CMS\Filesystem\*— moved toJoomla\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;afterdeclare/namespace- Vendor segment is the extension's own vendor — never
Joomla - Use statements grouped (Joomla CMS, Joomla Framework, third-party, project) and alphabetized
finalon 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 isHtmlView - Tables extend
Joomla\CMS\Table\Table, takeDatabaseDriverin constructor services/provider.phpreturns anonymous class implementingServiceProviderInterface- Component class implements
ComponentInterface
3. Security Standards
- All output escaped with
$this->escape()/htmlspecialchars() - All queries use prepared statements with
bind()andParameterType $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(), nounserialize()on untrusted input - File uploads validated for type, size, and destination
4. Database Operations
$this->getDatabase()in models; DI-injectedDatabaseInterfaceelsewhere — neverFactory::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.phpregistersMVCFactoryandComponentDispatcherFactorywith the correct namespace- Component sets
ComponentInterface::classin 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/onsubmithandlers
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 legacyclass="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
filterand (where applicable)validate
Quick Reference Checklist
File Header
<?php
/**
* @package Vendor.Component
* @subpackage com_example
*
* @copyright (C) [year] [Vendor Name]
* @license GNU General Public License version 2 or later; see LICENSE.txt
*/
declare(strict_types=1);
namespace Vendor\Component\Example\Administrator\Controller;
\defined('_JEXEC') or die;
Controller Pattern
// ✅ CORRECT — Joomla 6 native
use Joomla\CMS\MVC\Controller\FormController;
class ItemController extends FormController
{
protected $text_prefix = 'COM_EXAMPLE_ITEM';
}
// ❌ INCORRECT — FOF / Joomla 3
use F0FController; // Removed
class ItemController extends JController {} // Removed
Model Pattern (prepared statements)
// ✅ CORRECT
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);
// ❌ INCORRECT — SQL injection
$query->where('state = ' . $state);
View Pattern (XSS prevention)
// ✅ CORRECT
<?php echo $this->escape($item->title); ?>
// ❌ INCORRECT
<?php echo $item->title; ?>
Service Provider
// ✅ CORRECT — Joomla 6 DI
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'));
// ComponentInterface registration ...
}
};
Plugin Event Handler
// ✅ CORRECT — SubscriberInterface + typed event
final class Plugin extends CMSPlugin implements SubscriberInterface
{
public static function getSubscribedEvents(): array
{
return ['onContentPrepare' => 'onContentPrepare'];
}
public function onContentPrepare(ContentPrepareEvent $event): void
{
$item = $event->getItem();
// ...
}
}
// ❌ INCORRECT — legacy by-ref signature
public function onContentPrepare($context, &$article, &$params, $page = 0) { /* ... */ }
Database Access
// ✅ CORRECT
$db = $this->getDatabase(); // in models
$db = Factory::getContainer()->get(DatabaseInterface::class); // elsewhere
// ❌ INCORRECT
$db = Factory::getDbo(); // legacy
$db = JFactory::getDbo(); // removed
User Object (CRITICAL — Factory::getUser() removed in Joomla 6)
// ❌ REMOVED
$user = Factory::getUser();
$user = Factory::getUser($userId);
// ✅ Current user (in HtmlView subclasses)
$user = $this->getCurrentUser();
// ✅ Current user (in Controllers, Models, Plugins, Helpers)
$user = Factory::getApplication()->getIdentity();
// ✅ Load any user by ID
use Joomla\CMS\User\UserFactoryInterface;
$user = Factory::getContainer()->get(UserFactoryInterface::class)->loadUserById((int) $userId);
Filesystem Namespace (moved in Joomla 6)
// ❌ DEPRECATED
use Joomla\CMS\Filesystem\File;
use Joomla\CMS\Filesystem\Folder;
use Joomla\CMS\Filesystem\Path;
// ✅ JOOMLA 6
use Joomla\Filesystem\File;
use Joomla\Filesystem\Folder;
use Joomla\Filesystem\Path;
Web Asset Manager
// ✅ CORRECT
$wa = $this->getDocument()->getWebAssetManager();
$wa->useStyle('com_example.admin')
->useScript('com_example.admin');
// ❌ INCORRECT
HTMLHelper::_('script', 'com_example/admin.js', ...); // legacy
echo '<script src="..."></script>'; // raw injection
XML Form Field Formatting
<!-- ✅ CORRECT — one attribute per line, /> on its own line -->
<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>
<!-- ❌ INCORRECT — inline attributes, legacy class for boolean -->
<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 providersjoomla6-general-concepts— DI, ACL, DB, forms, routing, web assetsjoomla6-security— XSS, SQLi, CSRF, input handlingextension-build— official extension architecture
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, librariesmvc-checklist.md— controller/model/view/table compliance checklistsecurity-checklist.md— CSRF, SQLi, XSS, input, ACL, file upload checklistdatabase-patterns.md— query building, prepared statements, schema conventionsdi-patterns.md— service providers, container registration, constructor injectionlegacy-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
usestatement 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
Eventsubclass matches the subscribed event. - Mark unverifiable findings explicitly. Use
[UNVERIFIED — confirm before implementation]rather than guessing.
Resources
- Official Joomla Manual: https://manual.joomla.org/
- Joomla Coding Standards: https://developer.joomla.org/coding-standards.html
- Joomla API Documentation: https://api.joomla.org/