Create custom Site Health tasks

Apr 19, 2024
By myq for Developers

This tutorial outlines the integration of custom tests within the Site Health dashboard introduced in Concrete CMS version 9.2.0. Extending the existing Site Health functionalities allows developers to introduce bespoke tests tailored to specific needs, thereby enhancing the operational efficiency and monitoring capabilities of websites.In this tutorial, we will create a custom Site Health report in a package.

A full working example can be found as an installable package on GitHub: https://github.com/concretecms/site_health_report_example

Background

Site Health Dashboard introduced in version 9.2 includes three default reports: JavaScript scanner to check content for custom JavaScript, Production Mode readiness to asses whether any settings should be changed to safely run a production site (such as turning off debug mode), and Caching Mode readiness to assess how performant a site is going to be. The outcome of the checks depends on whether the site is set to production, staging, or development mode. Likewise, when a site is switched to production mode, running the Site Health checks will be an available option.

Afte the checks run, a report will be generated and kept for future reference. Any suboptimal findings can be corrected from the report by selecting the links for each finding.

This dashboard is designed to be extended with custom checks or tests to meet a site's specific needs. Each test is a Task behind the scenes, so understanding how they work is important.

Package Controller

Setup Package Controller (controller.php): - Creating a new package, or modifying an existing one, by declaring the namespace, dependencies, and package propertie in controller.php - In the on_start() method, register the custom health report with the task manager.

namespace Concrete\Package\SiteHealthReportExample;

use Concrete\Core\Package\Package;
use Concrete\Core\Command\Task\Manager as TaskManager;
use Concrete\Example\SiteHealthReport\Command\Task\Controller\SiteHealthReportExampleController;

class Controller extends Package {
    protected $pkgHandle = 'site_health_report_example';
    protected $appVersionRequired = '9';
    protected $pkgVersion = '0.1';
    protected $pkgAutoloaderRegistries = ['src' => '\Concrete\Example\SiteHealthReport'];

    public function on_start() {
        $manager = $this->app->make(TaskManager::class);
        $manager->extend('custom_site_health_report_example', function() {
            return new SiteHealthReportExampleController($this->getEntityManager());
        });
    }

    public function install()
    {
        parent::install();
        $this->installContentFile('install' . DIRECTORY_SEPARATOR . 'tasks.xml');
    }
}

Task Controller

Implement the Report Controller (src/Command/Task/Controller/SiteHealthReportExampleController.php): - Define the controller class that implements the Site Health report. This class should specify the name, description, command name, test suite, and grader.

namespace Concrete\Example\SiteHealthReport\Command\Task\Controller;

use Concrete\Core\Health\Report\ReportController;
use Concrete\Core\Health\Report\Test\SuiteInterface;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Suite\ExampleSuite;

class SiteHealthReportExampleController extends ReportController
{

    public function getName(): string
    {
        return t('Custom Site Health Report Example');
    }

    public function getConsoleCommandName(): string
    {
        return 'health:custom-report-example';
    }

    public function getDescription(): string
    {
        return t('Demonstrates how to add a custom Site Health report to a package.');
    }

    public function getTestSuite(): SuiteInterface
    {
        return new ExampleSuite();
    }

    public function getResultGrader(): ?GraderInterface
    {
        return new ProductionGrader();
    }
}

Define the Tests

Create Tests (src/Health/Report/Test/Test/CheckDayOfWeekTest.php): Each test should implement TestInterface and define its behavior within the run method. This example test is not useful; it just randomly selects a day of the week and compares it with the actual day of the week, however it shows how the test can return success or a warning.

namespace Concrete\Example\SiteHealthReport\Health\Report\Test\Test;

use Concrete\Core\Config\Repository\Repository;
use Concrete\Core\Health\Report\Runner;
use Concrete\Core\Health\Report\Test\TestInterface;
use Concrete\Example\SiteHealthReport\Health\Report\Finding\Control\Location\DashboardWelcomeLocation;
use DateTime;

class CheckDayOfWeekTest implements TestInterface
{

    protected $config;

    public function __construct(Repository $config)
    {
        $this->config = $config;
    }

    public function run(Runner $report): void
    {

        $results = [
            1 => 'Monday',
            2 => 'Tuesday',
            3 => 'Wednesday',
            4 => 'Thursday',
            5 => 'Friday',
            6 => 'Saturday',
            7 => 'Sunday'
        ];
        $result = (string) rand(1, count($results));
        $dow = (new DateTime())->format('N');
        if ($result === $dow) {
            $report->success(
                "Random day ({$results[$result]}) is the same as today ({$results[$dow]}).",
                $report->button(new DashboardWelcomeLocation())
            );
        }
        else {
            $report->warning(
                "Random day ({$results[$result]}) is not the same as today ({$results[$dow]}).",
                $report->button(new DashboardWelcomeLocation())
            );
        }
    }
}

Define links to resolve test issues

In the above example, a link is provided to the Dashboard Welcome page to further investgate or resolve the issue. This is accomplished by extending DashboardPageLocation:

namespace Concrete\Example\SiteHealthReport\Health\Report\Finding\Control\Location;

use Concrete\Core\Health\Report\Finding\Control\DashboardPageLocation;

class DashboardWelcomeLocation extends DashboardPageLocation
{

    public function getPagePath(): string
    {
        return '/dashboard/welcome';
    }

    public function getName(): string
    {
        return 'Dashboard Welcome';
    }
}

Define the Test Suite

Create Test Suites (src/Health/Report/Test/Suite/ExampleSuite.php): A test suite aggregates multiple tests. Like the example test in the previous section, these tests are just silly examples to show how they can be collected into a suite of tests.

namespace Concrete\Example\SiteHealthReport\Health\Report\Test\Suite;

use Concrete\Core\Health\Report\Test\Suite;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Test\CheckRandomTest;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Test\CheckTimeTest;
use Concrete\Example\SiteHealthReport\Health\Report\Test\Test\CheckDayOfWeekTest;

class ExampleSuite extends Suite
{

    public function __construct()
    {
        $tests = [
            CheckDayOfWeekTest::class,
            CheckRandomTest::class,
            CheckTimeTest::class,
        ];
        foreach ($tests as $test) {
            $this->add($test);
        }
    }
}

Register Tasks and Task Sets

XML Configuration (install/tasks.xml): - This XML file will be used during the installation or upgrade of the package to register new tasks and task sets within the system.

<concrete5-cif version="1.0">
    <tasks>
        <task handle="custom_site_health_report_example" package="site_health_report_example"/>
    </tasks>
    <tasksets>
        <taskset handle="site_health">
            <task handle="custom_site_health_report_example"/>
        </taskset>
    </tasksets>
</concrete5-cif>

Final Steps:

  • Install or Upgrade the Package: install or upgrade the package through the dashboard to register the new tasks.
  • Testing: After installation, test your Site Health report by navigating to the Dashboard's health section or using the CLI command concrete/bin/concrete5 c5:health:custom-report-example to run the test suite.
Recent Tutorials
Create custom Site Health tasks
Apr 19, 2024
By myq.

This tutorial will guide you through the creation of a new Site Health task

Reusing the same Express entity in multiple associations
Apr 11, 2024
By myq.

How to create and manage multiple associations in Express

Express Form Styling
Apr 11, 2024
By myq.

Different ways to style Express forms

Setting addon/theme version compatibility in the marketplace
Jan 9, 2024

For developers worn out with setting the latest addon or theme version manually across too many core versions, here is a JavaScript bookmarklet to do it for you.

How to get the locale of a page
Jan 8, 2024
By wtfdesign.

Now, why don't we just have a getLocale() method on Page objects beats me, but here's how you work around it

Using a Redis Server
Jun 16, 2023
By mlocati.

How to configure Concrete to use one or more Redis servers to persist the cache.

Improvements?

Let us know by posting here.