Work In Progress

This book is currently work in progress. Some sections are not yet written. Thank you for your understanding!

Dashboard

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]Note

<dashboards> is a top-level tag, directly under the <extension> root tag. Yes, even though it only applies in the component's administration (backend) section. If your Dashboard does not work first check that you have not accidentally put that tag under <administration>. It's the most common mistake!

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]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]Important

Your component manifest MUST ALSO follow the naming convention bareComponent.xml and be placed in the backend folder of your component. For example, com_example's XML manifest MUST be called example.xml and be found in administrator/components/com_example/example.xml.

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-com_example-something will appear in this dashboard 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=com_example.something where 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&amp;view=cpanel&amp;dashboard=com_example.something">
        COM_EXAMPLE_MENU_TITLE_DASHBOARD
      </menu>
    
      <!-- more submenu items -->
    </submenu>
    [Important]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. The dashboard 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]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 (administrator/components/com_users/presets/users.xml), copy it to administrator/templates/atum/html/com_menus/presets/users.xml and edit away!

Since all overrides live under the same com_menus/presets override folder you now understand why their name needs to be unique across all components installed on your site.

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&amp;view=categories&amp;extension=com_example"
      quicktask="index.php?option=com_categories&amp;extension=com_example&amp;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&amp;view=items"
      quicktask="index.php?option=com_example&amp;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 form none fa-something. This results in the CSS class being set to icon-none fa-something. There is no such thing as an icon-none CSS class, so that part does nothing. The next part, the fa-something, is where I tell the browser to use one of the available FontAwesome icons.

  • The quicktask and quicktask-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 attribute menu-quicktask-icon which works in the exact same way as a heading's icon 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]Tip

You can publish modules to your Dashboards by assigning them to a module position named something like cpanel-com-example-something where example is the name of your component without com_ and something is the name of your custom dashboard without the component prefix. The aforementioned example module corresponds to the dashboard com_example.something.

Likewise, Quick Icon modules can be assigned to a custom dashboard by publishing them to the module position icon-com-example-something following the same convention as above (you just replace cpanel with icon). Remember that Quick Icon modules are displayed above the other dashboard modules.