Extend Contao Backend Tables Safely with the Data Container Array
Add custom fields to tl_page or other Contao tables using DCA without editing core files, then verify the change in the backend.
18 Dec 2025, 21:00 UTC

You need a new option on a Contao page record—for example, a checkbox to hide a header on specific pages—but you do not want to edit Contao’s core files. The practical takeaway is to declare the field in your own extension using the Data Container Array (DCA), merge it into the global table definition, and verify it appears in the backend after clearing the cache. DCA is Contao’s declarative configuration for backend forms and list views; it defines labels, input types, permissions, and callbacks without touching core PHP.
Where DCA fits in Contao 4 and 5
In Contao 4.x and 5.x, extensions are Symfony bundles managed through Contao Manager. DCA configuration is usually loaded from bundle resources and merged into $GLOBALS['TL_DCA']['tl_table_name']['fields']. Contao 3 used a more direct include pattern, so the loading path depends on your installed version. Check the Contao version in the backend or Contao Manager before writing code.
Worked example: add a checkbox to tl_page
This example adds a checkbox field named hideHeader to the page table (tl_page). It does not create frontend output by itself; a template or module must read the value later.
File location depends on your bundle structure. A common pattern is a DCA file returned from bundle configuration or loaded in config.php. The paths below are placeholders; verify them in your installation.
<?php
// config/dca/tl_page.php (example path; verify in your installation)
return [
'tl_page' => [
'fields' => [
'hideHeader' => [
'label' => &$GLOBALS['TL_LANG']['MSC']['hideHeader'],
'exclude' => true,
'inputType' => 'checkbox',
'eval' => ['tl_class' => 'w50 clr'],
'sql' => 'char(1) DEFAULT \'\' NOT NULL',
],
],
],
];
Then merge the definition into the global DCA array, typically from the bundle’s configuration loader:
<?php
$customDca = require __DIR__ . '\'../config/dca/tl_page.php\';
foreach ($customDca as $table => $definition) {
$GLOBALS['TL_DCA'][$table]['fields'] = array_merge(
$GLOBALS['TL_DCA'][$table]['fields'] ?? [],
$definition['fields'] ?? []
);
}
Edit these files on the project filesystem with write access to your bundle directory. The sql key is declarative, so you still need to add the matching database column through your schema workflow or Contao’s install tool.
Expected check: open the Contao backend, edit a page, and look for the new checkbox in the form. If it does not appear, clear the Contao cache and reload.
Verify and diagnose
- Confirm the Contao version. DCA loading differs between branches such as Contao 4.4, 4.13, and 5.x, so match the pattern to your installation.
- Confirm the extension loads. Use Contao Manager or the backend module manager to verify the bundle is active.
- Clear the cache. Contao caches DCA, so backend changes may not appear until the cache is cleared or the extension is reinstalled.
- Inspect the merged array. In development, you can check that
$GLOBALS['TL_DCA']['tl_page']['fields']['hideHeader']exists, but remove debugging code before production.
Risk: editing core Contao files directly is not recommended because future updates can overwrite them. Keep DCA declarations in your bundle.
Limitations and trade-offs
- DCA changes the backend editing experience only. It does not automatically render the field on the frontend; you must update templates or modules.
- Extending core tables such as
tl_page,tl_article, ortl_contentcan complicate Contao updates if a future release changes the same table or field definitions. - Field definitions are cached, so changes may seem silent until the cache is cleared.
- Not every DCA option is covered in stable release notes across branches, so behavior can differ between versions.
A practical way to check the result: after clearing the cache, create or edit a record in the affected table, save it, and confirm the field value persists in the database and the backend form.
Closing
Start with one field in a non-core table if possible, verify the backend form, then extend core tables only when the use case justifies the update risk. Keep DCA declarations in your bundle, document the database column separately, and test after any Contao minor update.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.