Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

A list in the control panel

So far blog posts can be added only through phpMyAdmin. They should be managed by an administrator from the panel — that is what the administrator part of a component is for. It is built like the site part, but a screen has a toolbar with buttons. Let us make the first screen — the list of posts.

Files

Create four files by hand:

administrator/components/com_hello/
├── hello.xml
├── services/provider.php
├── src/
│   ├── Controller/
│   │   └── DisplayController.php
│   ├── Model/
│   │   └── PostsModel.php
│   └── View/
│       └── Posts/
│           └── HtmlView.php
└── tmpl/
    └── posts/
        └── default.php

Note the namespace: it has Administrator instead of Site.

The controller

// administrator/components/com_hello/src/Controller/DisplayController.php
namespace My\Component\Hello\Administrator\Controller;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\Controller\BaseController;
 
class DisplayController extends BaseController
{
    protected $default_view = 'posts';
}

The model

// administrator/components/com_hello/src/Model/PostsModel.php
namespace My\Component\Hello\Administrator\Model;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\Model\ListModel;
use Joomla\Database\QueryInterface;
 
class PostsModel extends ListModel
{
    protected function getListQuery(): QueryInterface
    {
        $db = $this->getDatabase();
 
        return $db->getQuery(true)
            ->select($db->quoteName(['id', 'title', 'published', 'created']))
            ->from($db->quoteName('#__hello_posts'))
            ->order($db->quoteName('id') . ' DESC');
    }
}

Unlike the site model, there is no published = 1 condition here: the administrator sees hidden posts too.

The view with a toolbar

// administrator/components/com_hello/src/View/Posts/HtmlView.php
namespace My\Component\Hello\Administrator\View\Posts;
 
defined('_JEXEC') or die;
 
use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView;
use Joomla\CMS\Toolbar\ToolbarHelper;
 
class HtmlView extends BaseHtmlView
{
    public array $items = [];
 
    public function display($tpl = null): void
    {
        $this->items = $this->getModel()->getItems();
 
        ToolbarHelper::title('Hello: posts');
        ToolbarHelper::addNew('post.add');
 
        parent::display($tpl);
    }
}

ToolbarHelper::title() sets the screen title, addNew() adds the New button. The post.add argument is the action the button submits: the add() method of the PostController controller. It appears in the next lesson.

The layout

<?php
// administrator/components/com_hello/tmpl/posts/default.php
 
defined('_JEXEC') or die;
 
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Router\Route;
?>
<form action="<?php echo Route::_('index.php?option=com_hello&view=posts'); ?>"
      method="post" name="adminForm" id="adminForm">
 
    <table class="table">
        <thead>
            <tr>
                <th>Title</th>
                <th>Published</th>
                <th>ID</th>
            </tr>
        </thead>
        <tbody>
            <?php foreach ($this->items as $item) : ?>
                <tr>
                    <td>
                        <a href="<?php echo Route::_('index.php?option=com_hello&task=post.edit&id=' . (int) $item->id); ?>">
                            <?php echo $this->escape($item->title); ?>
                        </a>
                    </td>
                    <td><?php echo $item->published ? 'Yes' : 'No'; ?></td>
                    <td><?php echo (int) $item->id; ?></td>
                </tr>
            <?php endforeach; ?>
        </tbody>
    </table>
 
    <input type="hidden" name="task" value="">
    <?php echo HTMLHelper::_('form.token'); ?>
</form>

A list in the panel is always wrapped in a form named adminForm. Toolbar buttons have no forms of their own: when pressed they write their action into the hidden task field and submit this form. HTMLHelper::_('form.token') adds a hidden field with a protection token.

The result

Open Components → Hello in the panel. Instead of an error you see the "Hello: posts" screen with a table of two posts and the New button. The button and the post links still lead to an error — there is no PostController yet.

Toolbar buttons

CallButton
ToolbarHelper::addNew('post.add')New
ToolbarHelper::save('post.save')Save & Close
ToolbarHelper::apply('post.apply')Save
ToolbarHelper::cancel('post.cancel')Close
ToolbarHelper::deleteList('', 'posts.delete')Delete the ticked rows
ToolbarHelper::preferences('com_hello')Component options

Actions on ticked rows — posts.delete, posts.publish — are handled by a list controller. It extends the ready-made AdminController class, and the table gets a column of checkboxes.

Common mistake

The form in the layout is given another name, or the hidden task field is forgotten. Toolbar buttons look for exactly the adminForm form and the task field in it — without them pressing New does nothing, and a JavaScript error appears in the browser console.

Thanks for reading!

Donate to the site — we work hard for you.