Skip to content

Add block_data() and block_export() functions - #4920

Open
seb-jean wants to merge 1 commit into
twigphp:3.xfrom
seb-jean:feature/block-export-data
Open

seb-jean wants to merge 1 commit into
twigphp:3.xfrom
seb-jean:feature/block-export-data

Conversation

@seb-jean

@seb-jean seb-jean commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds two new Twig functions that allow blocks to export structured data alongside their rendered HTML output:

  • block_export(data): called inside a block to store structured data on CoreExtension via a side-channel. The block continues to render HTML normally.
  • block_data(name): renders the block (HTML output is discarded) and returns the data exported via block_export(). Returns [] if the block does not call block_export().

Use case

Twig Components (<twig:> syntax) use the spread syntax ({{ ...hash }}) which requires an associative array — not an HTML string. Today, blocks like widget_attributes in Symfony's form themes render HTML attribute strings, making them incompatible with the <twig:> parser.

With block_data() / block_export(), a Symfony form theme block can export its attributes as a hash while still rendering HTML for backward compatibility:

{% block attributes %}
    {%- set attrs = {} -%}
    {%- for attrname, attrvalue in attr -%}
        {%- if attrvalue is same as(true) -%}
            {%- set attrs = attrs|merge({(attrname): attrname}) -%}
        {%- elseif attrvalue is not same as(false) -%}
            {%- set attrs = attrs|merge({(attrname): attrvalue}) -%}
        {%- endif -%}
    {%- endfor -%}
    {%- do block_export(attrs) -%}
    {%- for attrname, attrvalue in attrs -%}
        {{- ' ' ~ attrname }}="{{ attrvalue }}"
    {%- endfor -%}
{% endblock %}

A Twig Component form theme can then use:

<twig:Input type="{{ type }}" {{ ...block_data('widget_attributes') }} />

Implementation

  • block_data() uses a parser_callable to compile to a BlockDataExpression node (mirrors the block() / BlockReferenceExpression pattern)
  • BlockDataExpression compiles to $this->unwrap()->renderBlockData(...)
  • Template::renderBlockData() calls renderBlock() then returns the exported data from CoreExtension::getExportedBlockData()
  • The exported data is consumed on read (reset to null), preventing leaks between calls

Tests

4 test fixtures covering: basic usage, block override, block parent, and missing export fallback.

Closes #4919
Related: symfony/symfony#65713

These two functions allow blocks to export structured data alongside
their rendered HTML output, enabling use cases where the data built
inside a block is needed as a hash rather than as a string.

block_export(data) stores data on CoreExtension via a side-channel.
block_data(name) renders the block (discarding HTML) and returns
the exported data — or an empty array if no export was made.

This is particularly useful for Twig Component form themes where
the spread syntax ({{ ...hash }}) requires an associative array
instead of a rendered HTML attribute string.

See twigphp#4919
@seb-jean
seb-jean force-pushed the feature/block-export-data branch from 4b0964d to db70e37 Compare September 14, 2026 15:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Add block_data() and block_export() functions

1 participant