There is a new feature starting with Joomla 4: Dashboards.
Dashboards are sort of virtual pages, displayed by means of the com_cpanel core component, which allow the developer and the site owners to publish modules to customise them.
Define a dashboard
You can define one or more dashboards in your component's XML manifest file:
<dashboards> <dashboard title="COM_EXAMPLE_DASHBOARD_TITLE" icon="none fa fa-beer">com_example.something</dashboard> </dashboards>
![]() | Note |
---|---|
|
The title
attribute's value is a language string
defined in your extension's backend INI language file. It's customary for
its string to end with the word “Dashboard”, e.g.
COM_EXAMPLE_DASHBOARD_TITLE="Example Dashboard"
The value of the icon
attribute is a CSS class which
gives the dashboard page its icon. Joomla 4 loads FontAwesome 5 Free so
you can use any of its
icons. Please remember that Joomla prefixes the value of the
icon
attribute with the string literal icon-
.
This does not let you use all FontAwesome icons. To work around that I use
the value none fa fa-beer
which results in the HTML attribute
and value class="icon-none fa fa-beer"
. Since
icon-none
does not display anything, the browser falls back
to the next two CSS classes which render FontAwesome's beer mug
icon.
![]() | Warning |
---|---|
The Dashboard is not part of your component. It does not load any custom backend CSS you may have. As a result, you cannot display your logo or any custom image in the Dashboard. While you could do that by loading custom CSS in a module you set up in the dashboard, do keep in mind that the user can easily disable (unpublish) that module and then your CSS won't load anymore. If you opt for this trick it's a good idea to provide a fallback to a Joomla system icon class or a FontAwesome icon class to make sure that something is displayed as the Dashboard's title icon. |
The value inside the tag must be in the format
component.something
where component is the name of your
component (e.g. com_example
) and something is a unique
identifier for the dashboard among all dashboards defined in your
component. For example, we could have the dashboard
com_example.something
.
![]() | Important |
---|---|
Your component manifest MUST ALSO follow the naming convention
Keep in mind that Joomla automatically copies your component's XML manifest to the backend of your site when installing the component. You will only ever have to do it manually — if ever — when developing a component locally. |
The value of the tag after the dot is also important. All modules
published to the module position
cpanel-
will appear in this dashboard com_example
-something
com_example.something
.
Display a link to your dashboard in the component's submenu
The dashboard is cool… but how do you even display it? As it turns out there are exactly two ways:
-
Put a link (e.g. a Toolbar link button) in your extension pointing the browser to
index.php?index.php?option=com_cpanel&view=cpanel&dashboard=
wherecom_example.something
com_example.something
is your custom dashboard. -
Add a submenu item in your XML manifest, e.g.
<menu>COM_EXAMPLE</menu> <submenu> <menu link="index.php?option=com_cpanel&view=cpanel&dashboard=
com_example.something
">COM_EXAMPLE_MENU_TITLE_DASHBOARD
</menu> <!-- more submenu items --> </submenu>Important Remember that the
COM_EXAMPLE_MENU_TITLE_DASHBOARD
language string must be defined in your component's.sys.ini
language file. -
Super ultra secret stuff! Tell Joomla to display a Dashboard link next to your component's top-level menu entry. In your XML manifest you need to modify your top level menu item like so:
<menu> <params> <dashboard>com_example.something</dashboard> </params> COM_EXAMPLE </menu> <submenu> <!-- your submenu items here… --> </submenu>
The contents of the
params
menu subkey in the XML manifest goes through Joomla's Registry object and ends up, serialised as JSON, in the #__menu table record's params column. Thedashboard
key tells Joomla to display a dashboard link next to the menu item's text. Its value tells Joomla which dashboard to link to.
It is actually a good idea using a combination of the methods above.
The toolbar link can help lost users find their way back to the dashboard.
While the params
trick is cool, it only works in the default
components side menu. If the user has customised the menu, uses an
alternative presentation or simply visits the Components Dashboard they
won't see the link to your component's custom dashboard, therefore you may
need the second method (the submenu link to your dashboard) to cater for
these use cases. What can I say? Joomla is customisable. Maybe even a bit
too customisable.
A custom menu preset for your dashboard
You may have noticed that all core dashboards seem to have an
“immutable” area at the top. This is not immutable; it's just a plain old
module of the type mod_submenu
set to display in the module
style none
(that's why you don't see the cogs button to edit
it in the dashboard). You can of course edit this module like any other
module in Content, Administrator Modules.
It's useful that we can also do the same for our own component and its dashboard. However, you may notice that mod_submenu only has presets for core components. What about our custom component? Well, as it turns out, there are no hardcoded presets! Everything you see available in mod_submenu is, in fact, file on your site and yes, we can do the same thing for our own component!
We need to create a custom menu preset for our component by creating
an XML file under the
administrator/components/com_example/presets
folder.
To get an idea of what you can do, take a look at a core preset such as
administrator/components/com_users/presets/users.xml
.
The name of your menu preset XML file MUST be unique across all
components installed in Joomla. For this reason it's recommended to name
it after your extension. For example, com_example's menu preset would be
administrator/components/com_example/presets/example.xml
.
If you need multiple presets in your component it's strongly
recommended that their file names follow the pattern
component_something.xml
, e.g.
administrator/components/com_example/presets/example_alternate.xml
.
![]() | Tip |
---|---|
Per-component menu presets can be overridden in the same way as
view templates. For example, if you want to override the default core
Users menu preset
( Since all overrides live under the same
|
Here is a sample preset, let's say it's
administrator/components/com_example/presets/example.xml
(this means the preset name is example
) .
<?xml version="1.0"?> <menu xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:joomla.org" xsi:schemaLocation="urn:joomla.org menu.xsd" > <menuitem title="COM_EXAMPLE_MENUS_CONTENT" type="heading" icon="none fa-feather-alt" > <menuitem title="JCATEGORIES" type="component" element="com_categories" link="index.php?option=com_categories&view=categories&extension=com_example" quicktask="index.php?option=com_categories&extension=com_example&task=category.add" quicktask-title="COM_EXAMPLE_MENUS_NEW_CATEGORY" /> <menuitem title="COM_EXAMPLE_MENUS_ITEMS" type="component" element="com_example" link="index.php?option=com_example&view=items" quicktask="index.php?option=com_example&task=item.add" quicktask-title="COM_EXAMPLE_MENUS_NEW_ITEM" /> </menuitem> </menu>
Here are some practical tips:
-
The icon attribute sets the CSS class for the heading by combining the literal string
icon-
with the value of the attribute. The number of icons available that way is minuscule compared to the plethora of icons available in FontAwesome 5 Free. This is why I use values for this attribute in the formnone fa-something
. This results in the CSS class being set toicon-none fa-something
. There is no such thing as anicon-none
CSS class, so that part does nothing. The next part, thefa-something
, is where I tell the browser to use one of the available FontAwesome icons. -
The
quicktask
andquicktask-title
attributes set up the little quick action icon next to the menu item text. By default, this is a plus icon, implying that you can add an item. You can customise that icon using the attributemenu-quicktask-icon
which works in the exact same way as a heading'sicon
attribute.Why would you want to customise it? Well, let's say you have a security component with a view called Automatically Blocked IP Addresses. It would not make sense to manually add a new entry — since they are automatically blocked — but it would totally make sense to have a quick action to unblock an accidentally blocked IP address. In this case a more appropriate icon would be
fa-unlock
.
Creating and publishing the custom dashboard menu module, automatically
All right. We have a dashboard. We have a menu item to access it. We have a custom menu to display in a mod_submenu module inside the dashboard. But how exactly do we get to create this kind of module? We can't possibly ask our users to create it manually, that would suck!
The answer is that Joomla gives us ALMOST everything we need to create that module in our component's installation script.
First, let's make sure our component does use an installation script. In the XML manifest we need to add a line like this, as we're familiar from Joomla 3:
<scriptfile>script.example.php</scriptfile>
The script.example.php
will contain our component
installation script. You are familiar with that; it's been around since
Joomla 1.0.
What you may not have picked up is that since Joomla 3.6 there's a
superclass our installation script can extend from. In Joomla 3 it was
called JInstallerScript
, in Joomla 4 it's
Joomla\CMS\Installer\InstallerScript
(the old name
will work up to and including Joomla 5.3). We'll get into more detail on
it in the installation script
section.
Joomla's InstallerScript provides a handy method called
addDashboardMenu
which creates a
mod_submenu
module to a specific dashboard using a specific
menu preset. However, the way it is written it assumes that it will only
ever be executed once, the first time you install a component. What about
hundreds of third party components which have been around long before
Joomla 4? Don't worry, we have a solution! We will install the module if
and only if it's missing, regardless of whether this is a new installation
or an update.
Here's how to do that:
<?php defined('_JEXEC') || die; use Joomla\CMS\Factory; use Joomla\CMS\Installer\Adapter\PackageAdapter; use Joomla\CMS\Installer\InstallerScript; class Com_ExampleInstallerScript extends InstallerScript { /** * Called after any type of installation / uninstallation action. * * @param string $type Which action is happening (install|uninstall|discover_install|update) * @param PackageAdapter $parent The object responsible for running this script * * @return bool * @since 1.0.0 */ public function postflight(string $type, PackageAdapter $parent): bool { // Do not run on uninstall. if ($type === 'uninstall') { return true; } // Install the dashboard module if necessary $this->conditionalInstallDashboard('com-example-example', 'example'); return true; } private function conditionalInstallDashboard(string $dashboard, string $preset): void { $position = 'cpanel-' . $dashboard; /** @var \Joomla\Database\DatabaseDriver $db */ $db = Factory::getContainer()->get('DatabaseDriver'); $query = $db->getQuery(true) ->select('COUNT(*)') ->from($db->quoteName('#__modules')) ->where([ $db->quoteName('module') . ' = ' . $db->quote('mod_submenu'), $db->quoteName('client_id') . ' = ' . $db->quote(1), $db->quoteName('position') . ' = :position', ]) ->bind(':position', $position); $modules = $db->setQuery($query)->loadResult() ?: 0; if ($modules == 0) { $this->addDashboardMenu($dashboard, $preset); } } }
The postflight
method is called whenever
Joomla has finished trying to install or uninstall
(in Joomla 3 it was only after installation!) our component and before it
cleans up. At this point we can check if there is a module already
installed. If not, we let Joomla's code install it.
The only two things you need to change above are the parts in bold
type: the class name to match your component's name and the parameters to
the conditionalInstallDashboard
method. The
parameters are fairly obvious: the name of the dashboard (replacing the
underscore and dot with a dash!) and the name of your menu preset which
typically is the same as your component's name without the
com_
prefix.
![]() | Tip |
---|---|
You can publish modules to your Dashboards by assigning them to a
module position named something like
Likewise, Quick Icon modules can be assigned to a custom dashboard
by publishing them to the module position
|