elementor/tests/phpunit
Omer Israeli da77aee5b5
Internal: Twig-based rendering for div-block and flexbox containers [ED-23173] (#35475)
## Summary

Adds Twig template rendering for **e-div-block** and **e-flexbox**
elements, aligning them with the existing **atomic-tabs** approach for
unified editor/frontend rendering.

Gated behind a new hidden experiment: **e_twig_containers** (inactive by
default, dev release status).

### Jira
https://elementor.atlassian.net/browse/ED-23173

## Problem

Currently, `e-div-block` and `e-flexbox` render their HTML through PHP's
`before_render()` / `after_render()` methods. This means the editor
(JavaScript) and frontend (PHP) use completely different rendering
paths, making it difficult to achieve rendering parity. The
`atomic-tabs` element already solved this by using Twig templates — the
same template renders on both sides.

## Approach & Decisions

### 1. Extend, don't replace (backward compatibility)
- Created **`Div_Block_Twig`** and **`Flexbox_Twig`** PHP classes that
extend the original `Div_Block` and `Flexbox` classes
- These subclasses add the `Has_Element_Template` trait (same pattern as
`Atomic_Tabs`)
- When the experiment is **off**, the original classes are registered —
zero behavioral change
- When the experiment is **on**, the Twig variants are registered
instead

### 2. Twig templates handle dynamic HTML tags
- Both elements support configurable HTML tags (`div`, `a`, `button`,
`header`, etc.)
- The Twig template dynamically resolves the tag based on `settings.tag`
and `settings.link`
- Link elements switch to `<a>` tags; `button` tags use
`data-action-link` instead of `href`

### 3. Bug fix in editor element type override
- **Pre-existing bug found**: `init-legacy-views.ts` referenced
`elementsManager._elementTypes` but the actual property on the elements
manager is `elementTypes` (no underscore prefix)
- This bug was never triggered before because no nested-templated
element was also pre-registered by a separate JS module
- With the experiment on, `e-div-block` and `e-flexbox` become
nested-templated AND are pre-registered by `module.js` → the override
fallback path runs → crash on `undefined._elementTypes`
- **Fix**: `_elementTypes` → `elementTypes` in both
`init-legacy-views.ts` and `types.ts`

### 4. No JS changes needed for editor support
- The existing `init-legacy-views.ts` +
`create-nested-templated-element-type.ts` infrastructure automatically
detects that these elements now have `support_nesting` and Twig
templates in their config
- The editor will automatically override the basic JS registration with
the Twig-based view

## Files Changed

| File | Change |
|------|--------|
| `modules/atomic-widgets/module.php` | Register experiment, conditional
element registration |
| `modules/atomic-widgets/elements/div-block/div-block-twig.php` | New:
Twig variant of Div_Block |
| `modules/atomic-widgets/elements/div-block/div-block.html.twig` | New:
Twig template |
| `modules/atomic-widgets/elements/flexbox/flexbox-twig.php` | New: Twig
variant of Flexbox |
| `modules/atomic-widgets/elements/flexbox/flexbox.html.twig` | New:
Twig template |
| `packages/.../init-legacy-views.ts` | Fix: `_elementTypes` →
`elementTypes` |
| `packages/.../types.ts` | Fix: type definition to match runtime |
| `tests/.../test-twig-containers.php` | New: PHPUnit tests |

## How to Test

1. Activate the experiment:
   ```php
   // wp-config.php or via WP CLI
   update_option('elementor_experiment-e_twig_containers', 'active');
   ```
2. Open the Elementor editor, add a div-block or flexbox with child
widgets
3. **Editor**: Elements should render correctly in the canvas (Twig
rendering in editor)
4. **Frontend**: View the page — inspect HTML to confirm the wrapper
comes from the Twig template (same structure: `<div class="e-con
e-atomic-element ..." data-id="..." data-element_type="e-div-block"
...>`)
5. Test with a link configured (should switch to `<a>` or `<button>`
tag)
6. **Experiment off**: Verify everything still works as before (original
PHP rendering)

## Test Plan
- [x] PHPUnit tests for Twig element config (support_nesting, templates)
- [x] PHPUnit tests for rendering output (children, links, action links)
- [ ] Manual: Editor canvas renders elements correctly with experiment
on
- [ ] Manual: Frontend renders identical HTML to editor
- [ ] Manual: Experiment off = no behavioral change


Made with [Cursor](https://cursor.com)
<!--start_gitstream_placeholder-->
###  PR Description
## 1. Problem & Context

Introduces opt-in Twig templating for div-block and flexbox containers
to unify editor/frontend rendering logic and reduce PHP-side
duplication. Gated behind `e_twig_containers` experiment flag
(ED-23173), defaulting to inactive. Trade-off: adds template
registration overhead but consolidates rendering paths for
maintainability.

## 2. What Changed (Where)

- **`modules/atomic-widgets/module.php`**: Added experiment flag;
conditionally registers Twig variants vs. legacy classes
- **`modules/atomic-widgets/elements/base/has-element-template.php`**:
Introduced shared macros system (`get_shared_templates()`) for reusable
Twig helpers
- **`modules/atomic-widgets/elements/{div-block,flexbox}/*-twig.php`**:
New Twig-enabled subclasses extending legacy containers
- **`modules/atomic-widgets/elements/base/_macros.html.twig`**: Shared
Twig macros for attributes, classes, links
- **`modules/atomic-widgets/elements/{div-block,flexbox}/*.html.twig`**:
Twig templates mirroring PHP render logic
- **`packages/core/editor-canvas/src/legacy/*.ts`**: Fixed private
property access (`_elementTypes` → `elementTypes`)
-
**`tests/phpunit/elementor/modules/atomic-widgets/test-twig-containers.php`**:
Comprehensive parity tests vs. legacy output
- **`tests/bootstrap.php`**: Excluded `e_twig_containers` from
auto-activation in test suite

## 3. How It Works

Entry point: `Module::register_elements()` checks experiment flag and
registers either `Div_Block_Twig`/`Flexbox_Twig` or legacy classes. Twig
variants inherit base behavior, add `Has_Element_Template` trait, and
map templates via `get_templates()`. Shared `_macros.html.twig` provides
render helpers (`render_base_classes`, `render_link_attributes`, etc.).
Templates handle dynamic tag switching (`<a>` vs. `<button>` for action
links), matching legacy PHP logic. Template registration happens in
`Has_Element_Template::render()` before rendering, merging shared +
element-specific templates. TypeScript fix unblocks override behavior
when re-registering nested templated types.

## 4. Risks

**Template registration duplication**: `render()` loops through
templates on every render call; if templates are already registered,
early-continue prevents re-registration, but loop still executes.
Consider memoizing registration state per element type.

**Experiment exclusion in tests**: Excluding `e_twig_containers` from
auto-activation means Twig variants won't run in default test suite.
Intentional isolation, but verify coverage when flag flips to active.

**TypeScript property visibility change**: Changing `_elementTypes`
(private convention) to `elementTypes` (public) breaks encapsulation.
Acceptable for override use case, but downstream consumers may now
mutate internal state.

_Generated by LinearB AI and added by gitStream._
<sub>AI-generated content may contain inaccuracies. Please verify before
using.
💡 **Tip:** You can customize your AI Description using **Guidelines**
[Learn
how](https://docs.gitstream.cm/automation-actions/#describe-changes)</sub>
<!--end_gitstream_placeholder-->


[ED-23173]:
https://elementor.atlassian.net/browse/ED-23173?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ

---------

Co-authored-by: ElementorBot <48412871+elementorbot@users.noreply.github.com>
2026-04-19 16:03:13 +03:00
..
elementor Internal: Twig-based rendering for div-block and flexbox containers [ED-23173] (#35475) 2026-04-19 16:03:13 +03:00
resources Fix: V4 Fill on svg (#30310) 2025-02-20 12:28:40 +02:00
schemas Internal: Update consent handling for existing site data usage [ED-21470] (#33336) 2025-11-03 17:43:19 +02:00
trait-responsive-control-testing.php Fix: Custom background position not inherited on mobile and front end [ED-8329] (#19883) 2022-10-19 11:50:15 +03:00
trait-test-base.php DB: Deprecate - get_builder 2020-10-28 17:13:30 +02:00
trait-test-upgrades.php Internal: Improved functionality in Ajax Before Save Settings [ED-15700] (#29314) 2024-11-18 14:53:22 +04:00