From 207f8737392b4856734780f3accef76f2cfc9fd6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 27 Aug 2026 13:07:13 +0200 Subject: [PATCH 1/7] Document that include_only keeps global variables available --- doc/functions/include_only.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/functions/include_only.rst b/doc/functions/include_only.rst index be3ffe9a6..ab1399559 100644 --- a/doc/functions/include_only.rst +++ b/doc/functions/include_only.rst @@ -17,6 +17,9 @@ Variables from the active context are not passed implicitly. This makes the data a template relies on explicit, which is often clearer and easier to reason about. +Note that global variables (like the ones registered via ``addGlobal()``) are +not part of the context: they remain available in the included template. + Returned Value -------------- @@ -40,7 +43,7 @@ explicitly: .. code-block:: twig - {# template.html.twig will only have access to the "name" variable #} + {# template.html.twig only gets the "name" variable from the caller #} {{ include_only('template.html.twig', {name: 'Fabien'}) }} When passing a variable from the current context, you can use the following From 7bd052dd917b747d5759aea7151f7895cd4bdb00 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 27 Aug 2026 13:07:19 +0200 Subject: [PATCH 2/7] Merge overlapping CHANGELOG entries for the destructuring fatal error fix --- CHANGELOG | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index a3bc985c1..a3b240fff 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -3,8 +3,7 @@ * Add the `HtmlExtension::htmlAttrValue()` method to resolve a single HTML attribute value the way the `html_attr` function renders it * Fix `html_attr` JSON encoding a `Stringable` value in a `data-*` attribute instead of using its string representation * Add documentation comments to attach metadata to nodes (experimental) - * Fix destructuring patterns with no variables, including sequences containing only empty slots, triggering a PHP fatal error instead of a `SyntaxError` - * Fix an empty destructuring pattern triggering a PHP fatal error instead of a `SyntaxError` + * Fix destructuring patterns containing no variables (empty patterns or sequences with only empty slots) triggering a PHP fatal error instead of a `SyntaxError` * Fix object and mapping destructuring evaluating the right-hand expression more than once * Fix sequence destructuring of iterators throwing a `TypeError` * Add `TempestMarkdown` to use `tempest/markdown` as the `markdown_to_html` converter From 1205b8b6ca4b328dd0eb01975eab6a834d5d8e8e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 27 Aug 2026 13:07:26 +0200 Subject: [PATCH 3/7] Document that overriding MacroNode::compile() is not supported anymore --- doc/deprecated.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/deprecated.rst b/doc/deprecated.rst index 703dfed5f..668343c27 100644 --- a/doc/deprecated.rst +++ b/doc/deprecated.rst @@ -12,7 +12,10 @@ Classes final in Twig 4.0. Use ``Twig\Markup`` directly instead of extending it. * The ``Twig\Node\MacroNode`` class is considered final as of Twig 3.29 and - will be final in Twig 4.0. + will be final in Twig 4.0. Note that macros are compiled as closures stored + in a per-template registry as of Twig 3.29, so overriding + ``MacroNode::compile()`` based on the previous contract (emitting a + ``macro_``-prefixed method) is not supported anymore. Functions --------- From be220e6fd8be4bf2c654297215c6b91d8bae20c1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 27 Aug 2026 13:07:34 +0200 Subject: [PATCH 4/7] Warn about untrusted input with the default Tempest markdown converter --- doc/filters/markdown_to_html.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/filters/markdown_to_html.rst b/doc/filters/markdown_to_html.rst index 4218ed37c..b5e03d443 100644 --- a/doc/filters/markdown_to_html.rst +++ b/doc/filters/markdown_to_html.rst @@ -105,6 +105,13 @@ to another implementation (for instance ``ParsedownExtra``, which extends (``# Title``) instead, and any YAML front matter is parsed out of the rendered HTML rather than being rendered. +.. caution:: + + The output of the filter is marked as safe for HTML. The default + ``tempest/markdown`` converter passes raw HTML, raw ``@@ ... @@`` blocks, + and unsafe links through, so only use it on trusted input, or pass a + converter configured to sanitize its output to ``TempestMarkdown``. + When using ``twig/extra-bundle``, register your converter as the ``twig.markdown.default`` service to make it the one used by the filter: From abbdf82823c780f4caf56a7cde53436f25b9134f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 27 Aug 2026 13:07:41 +0200 Subject: [PATCH 5/7] Fix the html_attr documentation about iterables in data attributes --- doc/functions/html_attr.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/functions/html_attr.rst b/doc/functions/html_attr.rst index b80b31ee7..bfd6ffc76 100644 --- a/doc/functions/html_attr.rst +++ b/doc/functions/html_attr.rst @@ -124,10 +124,10 @@ Data Attributes --------------- For ``data-*`` attributes, a boolean ``true`` is converted to the string -``"true"``, and any non-scalar value is JSON-encoded. Two exceptions behave as -they do for any other attribute: an iterable is rendered as a token list, and -a ``Stringable`` object is cast to its string representation. When an object -is both, the iterable behavior wins. +``"true"``, and any non-scalar value is JSON-encoded, including arrays and +other iterables. The only exception is a ``Stringable`` object, which behaves +as it does for any other attribute: it is cast to its string representation, +or rendered as a token list when it is also iterable. .. code-block:: html+twig From 099fa3471a0d7dbec9f2530a4a078a5d690faf2e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 27 Aug 2026 13:07:47 +0200 Subject: [PATCH 6/7] Document that sequence destructuring consumes one value per pattern slot --- doc/templates.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/templates.rst b/doc/templates.rst index 5c0c4a013..a2f30f7c6 100644 --- a/doc/templates.rst +++ b/doc/templates.rst @@ -1216,8 +1216,9 @@ You can skip values by leaving a slot empty: Sequence destructuring also works with iterators (any ``Traversable`` value). Values are extracted in iteration order and keys are ignored. The -iterator is consumed lazily: only as many values as there are variables are -fetched, and the expression returns the iterator itself. +iterator is consumed lazily: only as many values as there are slots in the +pattern are fetched (an empty slot consumes a value too), and the expression +returns the iterator itself. Object Destructuring ~~~~~~~~~~~~~~~~~~~~ From 59f7d678483439159d88238cd5a30eb8e65d3c1c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 27 Aug 2026 13:43:07 +0200 Subject: [PATCH 7/7] Document that reusing a non-rewindable iterator after destructuring is unsupported --- doc/templates.rst | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/doc/templates.rst b/doc/templates.rst index a2f30f7c6..f81603ec3 100644 --- a/doc/templates.rst +++ b/doc/templates.rst @@ -1220,6 +1220,11 @@ iterator is consumed lazily: only as many values as there are slots in the pattern are fetched (an empty slot consumes a value too), and the expression returns the iterator itself. +Do not reuse a non-rewindable iterator (like a generator) after destructuring +it: Twig does not define the iteration state it is left in. A rewindable +iterator can be traversed again afterwards and restarts from the beginning, +according to its own behavior. + Object Destructuring ~~~~~~~~~~~~~~~~~~~~