Repository navigation
Migration 4.x to 5.0
Note
Canonical document:
docs/MIGRATION-4.x-TO-5.0.md.
For the 3.x rewrite migration see Migration 3.x β 4.0.
5.0 is additive. Every template that rendered under 4.x renders byte-identically under 5.0 β no syntax removed, no default changed, no behaviour reinterpreted. The major number reflects the size of the language addition (inline expressions reach into the substitution pipeline), not a compatibility break. There are no deprecations.
composer require paulmann/html-php:^5.0 # PSR-4 source
# β or copy php83/html.php (resp. php85/html.php) over the old bundleWordPress: replace wordpress/html-php/, then Tools β HTML.PHP β
Cache: clear once.
| Feature | 4.x | 5.0 |
|---|---|---|
| Math in a substitution tag | β β compute in @Set first |
β
%{= done / total * 100 | round:1 }
|
| Hash element by dynamic key | β β static dot paths only | β
%{= prices[currency]} Β· %{= rows[i].name}
|
| "Variable inside a variable" | β | β
%{= get(fieldName)} Β· %{= get('rows[1].name')}
|
| Arithmetic filters |
div only |
add sub mul div mod pow sqrt pct sum avg clamp |
| Expression functions | 17 | 23 (pow sqrt sum avg clamp get) |
a..b ranges in expressions |
broken (syntax error outside @Loop) |
β
fixed, indexable: %{= (1..3)[1]}
|
| Kill switch for inline math | β |
syntax.expressions: false (fail-closed) |
β Full guide: Expressions & Math
The = prefix is mandatory for expressions, and a bare payload keeps its
v4 meaning β including names with dashes:
%{a-b} β the variable literally named "a-b" (unchanged v4 lookup)
%{= a - b} β subtraction (new in v5)CSS/JS braces, @{} translations, filter chains, @If/@Set, SSI β all
untouched. The two internal renames (Scope::walk β public Scope::step,
Substitution constructor + Config\Limits) affect host code that
constructed those classes by hand; container-wired engines are unaffected.
<!-- 4.x -->
<!--@Set share="done / total * 100"-->
<div class="bar" style="width: %{share|round:0}%"></div>
<!-- 5.0 β same result, one tag -->
<div class="bar" style="width: %{= done / total * 100 | round:0}%"></div>Warning
The one trap: filter arguments are still literals (unchanged rule).
%{done|pct:total} divides by the string total β 0. The linter now
warns (filter-arg-not-numeric) and points at the %{= β¦} form.
Engine::create([
'syntax' => [
'expressions' => false, // refuse %{= β¦} outright (fail-closed)
'allow_raw_filter' => false, // no unescape hatch
'strict' => true, // template bugs throw, never half-render
],
'ssi' => ['exec_mode' => 'deny'],
]);With the gate closed, %{= β¦} tags stay visible in the output and record an
expr-disabled diagnostic β nothing is evaluated. @If/@Set remain
available (structural directives; a host that cannot trust a template with
@If cannot trust it at all). β Security Model
All hardening or bug fixes; none alter 4.x output:
-
Bounded AST memo β
Template\Expressionparse trees were memoized in an unbounded static array; now a 4 096-entry FIFO. -
Iteration budget β
count/sum/avg/instop at 100 000 items when walking a hostTraversable(an infinite generator used to hang). -
matchesviaSupport\Pcreβ backtrack-limit hits are clean no-matches. -
Range parsing fixed β
a..b/(1..3)in@If/@Set/%{=}threw "Trailing input" before (lexer/parser token-type mismatch);@Loopranges were and stay unaffected. -
INF/NAN-free arithmetic β
pow(0,-1),pow(10,9999),sqrt(-1), overflowing filter products all degrade to0. -
CLI option parser β
--var k=v(the documented space form) used to be silently dropped into positional args; both--key=valueand--key valuenow work for every option.
| Code | Where | Meaning |
|---|---|---|
expr-invalid |
diagnostics | malformed inline expression; tag kept visible |
expr-disabled |
diagnostics |
%{= β¦} met syntax.expressions: false
|
bad-expression |
lint (existing code, new source) |
%{= β¦} failed validation |
expressions-disabled |
lint |
%{= β¦} while the gate is off |
filter-arg-not-numeric |
lint (warning) | numeric filter argument looks like a variable |
HTML.PHP 5.0.0 Β· MIT Β© Mikhail Deynekin Β· Repository Β· Releases Β· Report a security issue
Wiki pages mirror docs/ β found a mistake? Edit the page or open an issue.
π Home Problem Domain Getting Started
Template Syntax Expressions & Math SSI Guide I18n Guide WordPress Integration CLI
Configuration API Cheatsheet Diagnostics & Troubleshooting
Architecture Security Model Testing & CI
πΊοΈ ROADMAP Migration 4.x β 5.0 Migration 3.x β 4.0 Contributing Repository β