Customizing Express Form
npx machina-cli add skill MacareuxDigital/concretecms-skills/customizing-express-form --openclawCustomizing Express Form
The Express Form is a core block type in Concrete CMS. You can customize the appearance of Express Forms by creating custom templates and overriding the default form context.
Creating a Form Context Class
To define custom template locations for Express Forms, start by creating a custom FrontendFormContext class. This class allows you to specify a custom attribute context.
<?php
namespace Application\Express\Form\Context;
use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
class FrontendFormContext extends CoreFrontendFormContext
{
public function getAttributeContext()
{
return new \Application\Attribute\Context\FrontendFormContext();
}
}
Applying the Custom Form Context Class
To use your custom Form Context, you must create a custom FormController class and register it within the context registry.
<?php
namespace Application\Express\Controller;
use Application\Express\Form\Context\FrontendFormContext;
use Concrete\Core\Express\Controller\StandardController;
use Concrete\Core\Express\Form\Context\FrontendFormContext as CoreFrontendFormContext;
use Concrete\Core\Form\Context\Registry\ContextRegistry;
class FormController extends StandardController
{
public function getContextRegistry()
{
return new ContextRegistry([
CoreFrontendFormContext::class => new FrontendFormContext()
]);
}
}
Register your custom controller as the standard controller for Express by adding the following code to your application's bootstrap or a package's on_start method:
$app->make(\Concrete\Core\Express\Controller\Manager::class)
->setStandardController(\Application\Express\Controller\FormController::class);
Customizing the Attribute Form
By using the custom FrontendFormContext class, you can define custom search paths for attribute templates.
<?php
namespace Application\Attribute\Context;
use Concrete\Core\Attribute\Context\FrontendFormContext as CoreFrontendFormContext;
use Concrete\Core\Filesystem\TemplateLocator;
class FrontendFormContext extends CoreFrontendFormContext
{
public function __construct()
{
parent::__construct();
$this->preferTemplateIfAvailable('custom');
}
public function setLocation(TemplateLocator $locator)
{
$locator->setTemplate('custom');
return $locator;
}
}
Template Overrides
With the configuration above, the following overrides become active:
application/attributes/attribute_handle/custom.phpoverrides the defaultconcrete/attributes/attribute_handle/form.php.application/elements/form/custom.phpoverrides the defaultconcrete/elements/form/bootstrap5.php.
Using Custom Templates in a Package
If you are developing a package, you can point the locator to your package directory in the Attribute FrontendFormContext class:
public function __construct()
{
parent::__construct();
// Look for 'custom.php' in the package first
$this->preferTemplateIfAvailable('custom', 'your_package_handle');
}
public function setLocation(TemplateLocator $locator)
{
// Enables packages/your_package_handle/elements/form/custom.php
$locator->setTemplate(['custom', 'your_package_handle']);
return $locator;
}
Also, you can enable overriding elements/express/form/form/form.php in your package by adding setLocation method in the Express Form FrontendFormContext class.
public function setLocation(TemplateLocator $locator)
{
$locator = parent::setLocation($locator);
$locator->prependLocation([
DIRNAME_ELEMENTS .
'/' .
DIRNAME_EXPRESS .
'/' .
DIRNAME_EXPRESS_FORM_CONTROLS .
'/' .
DIRNAME_EXPRESS_FORM_CONTROLS, // not a typo
'your_package_handle' // Package Handle
]);
return $locator;
}
Source
git clone https://github.com/MacareuxDigital/concretecms-skills/blob/main/customizing-express-form/SKILL.mdView on GitHub Overview
Express Form is a core block in Concrete CMS. You customize its appearance by creating a custom FrontendFormContext and a matching FormController, then overriding templates. This lets you change attribute inputs and form markup without touching core code.
How This Skill Works
You extend the core FrontendFormContext to define where templates are loaded and which attribute context to use. Then you build a FormController that returns a ContextRegistry mapping the core FrontendFormContext class to your custom one, and register this controller as the standard Express controller during startup. With template overrides in place (for example application/attributes/attribute_handle/custom.php and application/elements/form/custom.php), your custom templates are used when rendering forms.
When to Use It
- You need a custom look for Express forms without editing core templates.
- Building a package that ships its own Express form templates.
- You want a custom attribute form context to control attribute templates.
- You want to override specific Express form templates like attributes and elements.
- You need a centralized way to activate a custom form context via a FormController.
Quick Start
- Step 1: Create a FrontendFormContext that extends the core context and call preferTemplateIfAvailable('custom').
- Step 2: Implement a FormController that returns a ContextRegistry mapping CoreFrontendFormContext::class to your FrontendFormContext, then register it as the standard Express controller in bootstrap/on_start.
- Step 3: Add your templates at application/attributes/attribute_handle/custom.php and application/elements/form/custom.php (and package equivalents if using a package).
Best Practices
- Create a dedicated FrontendFormContext class in your app.
- Use preferTemplateIfAvailable('custom') to choose your template name.
- Implement setLocation on a TemplateLocator to point to your templates.
- Register your FormController in the ContextRegistry and set it as the standard controller on startup.
- Test overrides in both application and package contexts to avoid conflicts.
Example Use Cases
- Override application/attributes/attribute_handle/custom.php to replace the default form template.
- Override application/elements/form/custom.php to replace bootstrap5 form markup.
- Ship package templates by placing custom.php under packages/your_package_handle/elements/form/ and configuring the locator.
- Use preferTemplateIfAvailable and setLocation to point to package templates when packaged with a distribution.
- Register the FormController in on_start to activate the custom context across requests.