Create a Task

Add to Content XML

The easiest way to add task support to your packages is to use the Content XML format. Change your install method and add an upgrade like so:

public function install()

public function upgrade()

In doing so, you’ll ensure that the file tasks.xml is parsed on install and re-parsed in the event of an upgrade, ensuring that any new tasks you add are installed properly.

Now, create the tasks.xml file in the root of your package:

  • log_utilities
    • controller.php
    • tasks.xml

Use this for your XML content:

<?xml version="1.0" encoding="UTF-8"?>
<concrete5-cif version="1.0">

        <task handle="clear_log" package="log_utilities"/>
        <taskset handle="maintenance">
            <task handle="clear_log"/>


Let’s walk through what’s happening here. First, we’re instructing Concrete to install a task with the handle clear_log, and we’re also letting Concrete know that its a part of the log_utilities package, which we’ve already installed at this point. Next, we’re grouping that task underneath the existing Maintenance task set. If we wanted to, we could create a separate specific task set for the Log Utilities package using this tasksets XML instead:

<taskset handle="log_utilities" name="Log Utilities" package="log_utilities">
    <task handle="clear_log"/>

Create the Controller

Every task needs a Controller file. This file describes how the tasks works, what type of task it is, what commands to run when the task is invoked, and more. The easiest way to write your first task controller is based on an existing controller, and so that’s what we’re going to do here. Let’s create a file at packages/log_utilities/src/Command/Task/Controller/ClearLogController.php:

namespace Concrete\Documentation\LogUtilities\Command\Task\Controller;

use Concrete\Core\Command\Task\Input\InputInterface;
use Concrete\Core\Command\Task\Runner\CommandTaskRunner;
use Concrete\Core\Command\Task\Runner\TaskRunnerInterface;
use Concrete\Core\Command\Task\TaskInterface;
use Concrete\Core\Command\Task\Controller\AbstractController;

defined('C5_EXECUTE') or die("Access Denied.");

class ClearLogController extends AbstractController

    public function getName(): string
        return t('Clear Log');

    public function getDescription(): string
        return t('Clears the Concrete database log table..');

    public function getTaskRunner(TaskInterface $task, InputInterface $input): TaskRunnerInterface
        // Nothing here yet.


Let’s walk through this file. First, notice the namespace: we’re using the new custom namespace we registered in our package controller. There’s nothing special about this namespace - you can choose any namespace. You just need to make sure that it’s been added to your package controller for auto-loading, and that your support classes within your package’s src/ directory also correctly use this namespace.

Next, check out the name of the controller. Again, there’s nothing special about the name of the controller – you just need to ensure that it matches the filename, and make a note of what it is (you’ll need it later). After that, we define the name and description of our task, which will be shown in the Tasks dashboard interface.

Finally, we have the getTaskRunner method. This is a part of the general task interface. Additional methods are defined as a part of the task AbstractController, which we’re also inheriting.

Wire the Controller to the Manager

We still have one more thing we need to do before we can install the Log Utilities package and start writing our task. We need to register the task controller with the Concrete CMS Task manager. This happens in the on_start method within the package controller. Add this code to your package controller class:

use Concrete\Core\Command\Task\Manager as TaskManager;
use Concrete\Documentation\LogUtilities\Command\Task\Controller\ClearLogController;

You’ll need this because we’re going to work with these classes from within on_start. Next, add on_start to your package controller:

public function on_start()
    $manager = $this->app->make(TaskManager::class);
    $manager->extend('clear_log', function () {
        return new ClearLogController();

Install the Package

Now, we can install the package from the Dashboard or the command line:

Once installed, our package is available from within the Tasks Dashboard page:

And automatically from the command line as well. If you run concrete/bin/concrete from the web root of your Concrete site, you’ll see your task ready to run:

Make Your Task Do Something

With all of the boilerplate out of the way, we can start to focus on making our task actually do something when run.