Add twig support - #1584
Open
zonky2 wants to merge 15 commits into
Open
Conversation
A matching Twig template "@Contao/metamodels/<group>/<leaf>.html.twig" now takes precedence over the legacy ".html5" template, mirroring Contao core. When no Twig template exists the legacy template is used unchanged (full BC fallback). The new MetaModels\Render\TwigTemplateSurrogate resolves the candidate via Contao's managed "@contao" filesystem loader (so the templates are Template Studio ready and support theme and project overrides) and renders it through Twig with a context built by Contao's ContextFactory. MetaModels\Render\Template consults it before including the PHP template; the render group (attribute, filter, item) is passed by the callers via TemplateFactory::createTemplate(). Only the visual "html5" format is a Twig candidate - the plain text format used for the search index and sorting stays on the PHP engine. Precedence applies in the front end and the back end. See docs/twig-templates.md for the naming scheme and how packages ship templates (twig/ namespace root with a .twig-root marker).
…through the surrogate Ship the first core Twig templates under the namespace root Resources/contao/templates/twig/.twig-root: - metamodels/item/prerendered.html.twig (from metamodel_prerendered.html5) - metamodels/filter/default.html.twig (from mm_filteritem_default.html5) FrontendFilter::renderWidget() now renders the filter widget through MetaModels\Render\Template (via TemplateFactory, group "filter") instead of a raw Contao FrontendTemplate, so filter widgets use the same @Contao/metamodels/filter/<leaf> scheme as attributes and items. Verified in the front end: item list and filter widgets render through Twig with correct output (labels, values, actions) and fall back to the legacy .html5 templates where no Twig template exists.
Ship the remaining core item and filter Twig templates: - item/unrendered, item/prerendered_debug - filter/checkbox, filter/radiobuttons, filter/linklist, filter/datepicker (each extends filter/default via Twig block inheritance) Transitional back-compat (deprecated, to be removed in 3.0 with the .html5 templates): a legacy override of the flat template name in the project "templates/" directory (or a theme folder) keeps precedence over a bundle provided Twig template, so existing customisations keep working after the upgrade. Template::hasLegacyTemplateOverride() detects such overrides using the kernel project directory, which is now injected via TemplateFactory instead of being fetched from the container. Verified in the front end across several list pages (HTTP 200).
Provide Twig versions of the Contao content element / module wrapper templates (flat @contao identifiers): ce_metamodel_list, mm_filter_default, mm_clearall_default and the pagination template mm_pagination. The item templates now include the separate @Contao/mm_actionbutton.html.twig instead of inlining the markup, so existing custom action button templates keep overriding it.
Cover MetaModels\Render\TwigTemplateSurrogate: the html5-only format gate, the empty group and missing template short-circuits, precedence of a higher priority legacy .html5 template, rendering the Twig template when it exists, and the identifier mapping (metamodels/<group>/<leaf>) for the attribute, filter and item groups including the prefix stripping.
Contao 5.7 renders be_wildcard through an auto-escaping Twig template, so the
HTML info text built for the MetaModels content element / module preview
("MM: …", "Fi: …") showed up as escaped source in the back end list. Wrap the
info text in a Twig Markup instance so it is treated as safe HTML by the Twig
be_wildcard template while still rendering correctly via the legacy .html5 one.
Contao 5.7 marks Backend.getScrollOffset() as deprecated and will drop it in Contao 6. The global and row operations of the MetaModels tables carried it as an inline onclick handler, so the back end kept emitting the deprecated call on every list view. All 27 occurrences across the eleven DCA files now use the Stimulus controller instead: data-action="contao--scroll-offset#store". On the delete operations the confirmation stays in place as a plain onclick - it is no MooTools API and Contao itself combines both attributes the same way in tl_files.php.
The previous pass only covered the static DCA files. The commands of the item tables are built at runtime, so every MetaModel kept emitting the deprecated Backend.getScrollOffset() on its copy, cut and delete buttons - visible for instance in the hierarchy and variant tree views. CommandBuilder now hands out data-action="contao--scroll-offset#store" for those, with the confirmation of the delete command kept as a plain onclick, and the edit operation that LoadDataContainer adds to a parent table pointing at a MetaModel follows the same scheme.
Backend.toggleCheckboxes() is deprecated in Contao 5.7 and will be dropped in Contao 6. The "select all" switch of the add-all dialog now uses the contao--check-all Stimulus controller, which adds shift range selection on top. Only the attribute checkboxes carry the target attribute, so the "activate" option next to the switch is no longer toggled along with them.
The template hooked its setup into the MooTools "domready" event. Contao only keeps that event alive as a compatibility bridge - backend.js re-fires it on "turbo:render" - and it goes away with Contao 6. The setup now runs directly and registers for "turbo:render" itself, the same way the core Stimulus controllers do. The listener drops itself as soon as its field is gone, so it does not pile up while navigating, and a new guard bails out when the editor div already exists, which prevents a second editor when Turbo restores a cached page. Contao's own contao--ace controller is deliberately not used: it recomputes maxLines from the window height after the config callback and would override the number of rows that can be configured per attribute in MetaModels.
zonky2
force-pushed
the
hotfix/fix_twig_support
branch
from
July 27, 2026 16:27
c4d0eab to
6aec428
Compare
So far only the visual "html5" format could be surrogated; the plain text format (search index, sorting, group headers, alias generation) always stayed on the PHP engine. Its templates carry an additional ".text" in the name: "<leaf>.text.html.twig" surrogates the legacy "<leaf>.text". The doubled extension is not cosmetic. Contao derives the template identifier by stripping the trailing ".html.twig" resp. ".twig" and refuses to mix types under one identifier, so a "<leaf>.text.twig" beside a "<leaf>.html.twig" would share the identifier and make ContaoFilesystemLoader abort the whole hierarchy with an OutOfBoundsException - back end and front end would answer with HTTP 500. The naming is already established by the notelist mail template. A project side "templates/<leaf>.text" keeps its precedence, the same way it does for the visual format. The test for the previously unsupported format now uses a format that really is unsupported, and two new ones cover the text variant.
The two lines were kept apart while both were in flight: the Twig template support on this branch, the removal of the deprecated MooTools back end calls on hotfix/mootools-removal. They never touched the same file, so this merge is clean. Brings in the scroll offset replacement in the static DCAs and in the commands built at runtime, the check box toggle of the add-all dialog and the ACE editor initialisation.
The table has no list view: its data provider aggregates all rows of a MetaModel into a single record and refuses to fetch a collection. It never said so, so anything routing to its list ran into that refusal - visible as a 500 after "save and close", and on the list url itself. dc-general already acts on config/forceEdit: the list handler forwards to the edit action, and the back url leaves the table behind. Setting the flag is all that was missing.
This reverts commit d5a04fb.
The attribute disabled Turbo Drive for every MetaModels back end page and carried no reason beyond "for the time being". The reason has meanwhile been found and addressed where it belongs: dc-general excludes its own forms, because Turbo discards the answer to an auto submit, and that is what display conditions ride on. Everything else keeps working with Turbo - verified across the whole harness, see docs/turbo.md in the dc-general for the measurement.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.