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
Customize locale icons
Oct 29, 2024
By myq.

How to customize locale (language region) flags

Concrete CMS Caching Guide
Oct 16, 2024

An overview of types of caching in Concrete and considerations when using them.

Redirect all requests to HTTPS
Oct 9, 2024
By myq.

How to follow best practices for a secure web

Upgrade Concrete versions 9.3.1 and 9.3.2
Sep 10, 2024
By myq.

How to get past a bug in versions 9.3.1 and 9.3.2 that prevents upgrading the Concrete core through the Dashboard

How to use Composer with Marketplace extensions
Aug 22, 2024

Composer can be used to manage third-party extensions from the marketplace

Controlling Google Tag Manager Tags Based on Concrete CMS Edit Toolbar Visibility
Aug 13, 2024

This document provides a step-by-step guide on how to control the firing of Google Tag Manager (GTM) tags based on the visibility of the Concrete CMS edit toolbar. It explains how to create a custom JavaScript variable in GTM to detect whether the edit toolbar is present on a page and how to set up a trigger that ensures GTM tags only fire when the toolbar is not visible. This setup is particularly useful for developers and marketers who want to ensure that tracking and analytics tags are not activated during content editing sessions, thereby preserving the accuracy of data collected.

Improvements?

Let us know by posting here.