Joomla Custom Component Development
A component is the main unit of Joomla functionality. Controls the main content area of a page. Has two parts: Site (frontend) and Administrator (backend). Examples: com_content (articles), com_users (users), com_contact (contacts).
Joomla 5 Component Architecture
Joomla 5 uses MVC with Namespace and PSR-4:
com_catalog/
├── catalog.xml # Manifest
├── administrator/
│ └── components/
│ └── com_catalog/
│ ├── src/
│ │ ├── Controller/ # Controllers
│ │ ├── Model/ # Models
│ │ ├── View/ # Views
│ │ └── Table/ # Database tables
│ ├── tmpl/ # Templates
│ └── services/
│ └── provider.php # DI Provider
└── components/
└── com_catalog/
├── src/
│ ├── Controller/
│ ├── Model/
│ └── View/
└── tmpl/
Manifest (catalog.xml)
<?xml version="1.0" encoding="utf-8"?>
<extension type="component" version="4.0">
<name>Product Catalog</name>
<namespace path="src">MyCompany\Component\Catalog</namespace>
<version>1.0.0</version>
<files folder="components/com_catalog">
<filename>index.html</filename>
<folder>src</folder>
<folder>tmpl</folder>
</files>
<administration>
<files folder="administrator/components/com_catalog">
<filename>index.html</filename>
<folder>src</folder>
<folder>tmpl</folder>
<folder>services</folder>
</files>
<menu img="class:catalog">Catalog</menu>
</administration>
<install>
<sql>
<file driver="mysql" charset="utf8">sql/install.mysql.sql</file>
</sql>
</install>
<uninstall>
<sql>
<file driver="mysql" charset="utf8">sql/uninstall.mysql.sql</file>
</sql>
</uninstall>
</extension>
DI Service Provider
// administrator/components/com_catalog/services/provider.php
namespace MyCompany\Component\Catalog\Administrator\Service;
use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\Extension\Service\Provider\ComponentDispatcherFactory;
use Joomla\CMS\MVC\Factory\MVCFactory;
use Joomla\DI\Container;
use Joomla\DI\ServiceProviderInterface;
return new class implements ServiceProviderInterface {
public function register(Container $container): void {
$container->registerServiceProvider(new ComponentDispatcherFactory('\\MyCompany\\Component\\Catalog'));
$container->registerServiceProvider(new MVCFactory('\\MyCompany\\Component\\Catalog'));
}
};
Model
// components/com_catalog/src/Model/ProductsModel.php
namespace MyCompany\Component\Catalog\Site\Model;
use Joomla\CMS\MVC\Model\ListModel;
class ProductsModel extends ListModel {
protected function getListQuery(): \Joomla\Database\QueryInterface {
$db = $this->getDatabase();
$query = $db->getQuery(true);
$query->select(['p.id', 'p.title', 'p.price', 'p.sku', 'p.category_id', 'c.title AS category_name'])
->from($db->quoteName('#__catalog_products', 'p'))
->join('LEFT', $db->quoteName('#__catalog_categories', 'c') . ' ON c.id = p.category_id')
->where($db->quoteName('p.published') . ' = 1');
// Filter by category
$categoryId = $this->getState('filter.category_id');
if ($categoryId) {
$query->where($db->quoteName('p.category_id') . ' = ' . (int) $categoryId);
}
// Search
$search = $this->getState('filter.search');
if ($search) {
$query->where($db->quoteName('p.title') . ' LIKE ' . $db->quote('%' . $search . '%'));
}
$query->order($db->quoteName($this->getState('list.ordering', 'p.title')) . ' ' . $this->getState('list.direction', 'ASC'));
return $query;
}
}
View
// components/com_catalog/src/View/Products/HtmlView.php
namespace MyCompany\Component\Catalog\Site\View\Products;
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Factory;
class HtmlView extends BaseHtmlView {
protected array $items = [];
protected object $pagination;
protected object $state;
public function display($tpl = null): void {
$model = $this->getModel();
$this->items = $model->getItems();
$this->pagination = $model->getPagination();
$this->state = $model->getState();
// Add toolbar for administrators
if (Factory::getApplication()->isClient('administrator')) {
$this->addToolbar();
}
parent::display($tpl);
}
protected function addToolbar(): void {
$toolbar = \Joomla\CMS\Toolbar\ToolbarHelper::class;
$toolbar::title('Product Catalog', 'catalog');
$toolbar::addNew('product.add');
$toolbar::deleteList('', 'products.delete');
}
}
View Template
// components/com_catalog/tmpl/products/default.php
defined('_JEXEC') or die;
use Joomla\CMS\HTML\HTMLHelper;
?>
<div class="catalog-products">
<?php foreach ($this->items as $item) : ?>
<div class="catalog-product-card">
<h3 class="product-title">
<a href="<?php echo \Joomla\CMS\Router\Route::_('index.php?option=com_catalog&view=product&id=' . $item->id); ?>">
<?php echo htmlspecialchars($item->title, ENT_QUOTES, 'UTF-8'); ?>
</a>
</h3>
<p class="product-price"><?php echo number_format($item->price, 2, '.', ' '); ?> ₽</p>
<p class="product-category"><?php echo htmlspecialchars($item->category_name); ?></p>
</div>
<?php endforeach; ?>
<?php echo $this->pagination->getListFooter(); ?>
</div>
Timeline
Custom component development with CRUD operations, list and detail page, backend management — 2–3 weeks.







