PHPackages                             enlivenapp/vision - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Templating &amp; Views](/categories/templating)
4. /
5. enlivenapp/vision

ActiveLibrary[Templating &amp; Views](/categories/templating)

enlivenapp/vision
=================

Lightweight template engine with auto-escaping, extends, includes, filters, and custom tags

1.0.2(2mo ago)072MITPHPPHP ^8.1

Since Apr 20Pushed 2mo agoCompare

[ Source](https://github.com/enlivenapp/Vision)[ Packagist](https://packagist.org/packages/enlivenapp/vision)[ RSS](/packages/enlivenapp-vision/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (1)DependenciesVersions (4)Used By (2)

[![Stable? Not Quite Yet](https://camo.githubusercontent.com/8712c441bb32fd8db507e0008c5d13e30def50064f8fcbc689fbcf5191f7d2af/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f737461626c652533462d6e6f7425323071756974652532307965742d626c75653f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/enlivenapp/vision)[![License](https://camo.githubusercontent.com/36d6613fe99a2b440b637078af5dd53d2f7fa958c606dcf9958d95cb127741bc/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f656e6c6976656e6170702f766973696f6e3f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/enlivenapp/vision)[![PHP Version](https://camo.githubusercontent.com/6a1fd0cd0ca3950a4d7223f886164130a8d160cfe5d8b21e6ec35944a0c398c5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f656e6c6976656e6170702f766973696f6e3f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/enlivenapp/vision)[![Monthly Downloads](https://camo.githubusercontent.com/ac94704f723b4deeadc14ef4cfe2b3ab3f4d0ef91565d875fe9aba6a8c18f265/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646d2f656e6c6976656e6170702f766973696f6e3f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/enlivenapp/vision)[![Total Downloads](https://camo.githubusercontent.com/1e129b38d8fd38397dd1642adfaeb4bce95d77d96fcb4048d7324c66e93dd2e4/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f656e6c6976656e6170702f766973696f6e3f7374796c653d666f722d7468652d6261646765)](https://packagist.org/packages/enlivenapp/vision)[![GitHub Issues](https://camo.githubusercontent.com/b9099941f85127a924ee2f3df48f0c51e302fd13c55130735b55a7e46e83cc7b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f656e6c6976656e6170702f566973696f6e3f7374796c653d666f722d7468652d6261646765)](https://github.com/enlivenapp/Vision/issues)[![Contributors](https://camo.githubusercontent.com/b8e2b9c92e4726e66a04ab5bc002c98285dee7d15fbdd80ad89d5a8d8b1f9706/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f636f6e7472696275746f72732f656e6c6976656e6170702f566973696f6e3f7374796c653d666f722d7468652d6261646765)](https://github.com/enlivenapp/Vision/graphs/contributors)[![Latest Release](https://camo.githubusercontent.com/ff498222c454ca97a6817c5fbd0c08d840b24fab2966bc15ba663b12c3c9a1ce/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f656e6c6976656e6170702f566973696f6e3f7374796c653d666f722d7468652d6261646765)](https://github.com/enlivenapp/Vision/releases)[![Contributions Welcome](https://camo.githubusercontent.com/9db3f8b82ea88469efd296a9305fc00f40b4c9450bb6b539d42d339fa6963444/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6e747269627574696f6e732d77656c636f6d652d626c75653f7374796c653d666f722d7468652d6261646765)](https://github.com/enlivenapp/Vision/pulls)

Vision
======

[](#vision)

Lightweight, framework-agnostic PHP template engine with auto-escaping, template inheritance, includes, filters, and custom tags.

Requirements
------------

[](#requirements)

- PHP 8.1+

No framework dependencies. Works with any PHP project.

Installation
------------

[](#installation)

```
composer require enlivenapp/vision
```

Quick Start
-----------

[](#quick-start)

Create the engine once, optionally register any custom tags or filters your app needs, then render `.tpl` files:

```
use Enlivenapp\Vision\Engine;

$vision = new Engine();

// Optional: register custom tags (callable inside {% %})
$vision->tags()->register('base_url', fn(string $path = '') => '/myapp/' . ltrim($path, '/'));
$vision->tags()->register('current_year', fn() => date('Y'));

// Optional: register custom filters (used with | in templates)
$vision->filters()->register('slug', fn($val) => strtolower(preg_replace('/[^a-z0-9]+/i', '-', $val)));

echo $vision->render('/path/to/views/page.tpl', [
    'title' => 'My Page',
    'items' => ['one', 'two', 'three'],
    'user'  => ['name' => 'Admin', 'email' => 'admin@example.com'],
]);
```

That's the full lifecycle. The rest of this document covers template syntax and the engine API in detail.

Template Syntax
---------------

[](#template-syntax)

Vision templates are plain `.tpl` files. Four delimited constructs are recognized — everything outside them is emitted verbatim.

DelimiterPurpose`{{ ... }}`Output an expression, auto-escaped`{! ... !}`Output an expression, raw (no escaping)`{% ... %}`Control flow, blocks, includes, extends, and custom tags`{# ... #}`Comments (stripped during lexing — never reach output)### Output

[](#output)

`{{ ... }}` is the default output form. Results are passed through `htmlspecialchars()` with `ENT_QUOTES | ENT_SUBSTITUTE` and UTF-8, so output is safe by default:

```
{{ variable }}           Auto-escaped
{{ user.name }}          Dot-notation into arrays or objects
{{ user.profile.bio }}   Nested access at any depth
```

If any step in a dot-notation chain is missing, the whole expression resolves to `null` silently.

Use `{! ... !}` when you *intentionally* want unescaped output (e.g. pre-rendered HTML from a trusted source):

```
{! article_html !}
```

### Variables, literals, and expressions

[](#variables-literals-and-expressions)

Inside output and `{% %}` tags, Vision accepts:

- **Variables** — `user`, `user.name`, `items.0.title`
- **String literals** — `'hello'` or `"world"` (either quote style; `\` escapes the next character)
- **Number literals** — `42`, `3.14`
- **Keyword literals** — `true`, `false`, `null`

### Conditionals

[](#conditionals)

Branch on a truthy/falsy expression. `elseif` and `else` are optional.

```
{% if show_banner %}
    Banner
{% endif %}

{% if user %}
    Hello {{ user.name }}
{% else %}
    Please log in
{% endif %}

{% if role == 'admin' %}
    Admin panel
{% elseif role == 'editor' %}
    Editor tools
{% else %}
    Read only
{% endif %}
```

Supported operators: `==`, `!=`, `>`, `=`, `render(
    '/app/modules/blog/views/post.tpl',
    $data,
    '/app/shared/views/'   // includes/extends resolve from here
);
```

### `Engine::filters(): FilterRegistry`

[](#enginefilters-filterregistry)

Returns the filter registry. Call `->register(string $name, callable $callback)` to add custom filters.

### `Engine::tags(): TagRegistry`

[](#enginetags-tagregistry)

Returns the tag registry. Call `->register(string $name, callable $callback)` to add custom tags.

File Extension
--------------

[](#file-extension)

Templates use the `.tpl` extension by convention. Include and extends names have `.tpl` appended automatically if not present, so both `{% include 'partials/sidebar' %}` and `{% include 'partials/sidebar.tpl' %}` resolve to the same file.

Security
--------

[](#security)

- **Auto-escaping** — all `{{ }}` output is escaped with `htmlspecialchars()` using `ENT_QUOTES | ENT_SUBSTITUTE` and UTF-8 encoding.
- **Raw output is deliberate** — unescaped output requires the distinct `{! !}` syntax, so it's never accidental.
- **No PHP execution** — templates cannot evaluate arbitrary PHP. The expression grammar only supports variable lookup, literals, comparisons, boolean logic, and registered filters/tags.
- **Path-traversal protection** — include and extends template names containing `..` or null bytes resolve to empty and are never read from disk.
- **Comments stripped at lex time** — `{# ... #}` content is discarded before parsing and never reaches output.

Notes &amp; Gotchas
-------------------

[](#notes--gotchas)

These are the specific behaviors most likely to surprise you. Nothing here is a bug — each is intentional — but they're worth knowing up front.

- **Truthiness is custom, not PHP-standard.** Inside `{% if %}`, the values `null`, `false`, `''`, `0`, `'0'`, and `[]` are falsy; everything else is truthy. This matches most template engines.
- **`default` does not treat `0` as empty.** `{{ count | default('none') }}` renders `0` when `count` is zero, not `'none'`. Only `null`, `''`, and `false` trigger the fallback. If you need a broader "emptiness" check, write a custom filter.
- **Missing things fail silently.** Missing variables resolve to `null`. Missing includes, missing extends parents, missing top-level templates, unregistered tags, and unknown filters all produce empty output with no warning. This keeps partial renders alive but means typos can go unnoticed — check your output, or wrap `render()` with your own logging if you need strictness.
- **`{% include ... with { ... } %}` requires a quoted template name.** `{% include 'card' with {x: 1} %}` works; `{% include card with {x: 1} %}` does not — the `with` clause is dropped and the name is taken literally. Plain includes without a `with` clause accept quoted or unquoted names.
- **Only the first `{% extends %}` is honored.** A template cannot extend multiple parents; any extra `extends` statements are ignored.
- **The `raw` filter only matters as the last filter on `{{ }}`.** `{{ html | raw }}` skips escaping. `{{ html | raw | upper }}` does **not** — the last filter is `upper`, not `raw`. For raw output, prefer the `{! !}` delimiter; it's clearer.
- **`nl2br` output needs `{! !}`.** `{{ text | nl2br }}` will escape the inserted `` tags back into `&lt;br&gt;`. Use `{! text | nl2br !}` for the intended effect.
- **`.tpl` is appended automatically.** You don't need to include the extension in `include` / `extends` names unless you want to — both forms work.
- **`true`, `false`, `null` are literals.** `{% if active == true %}` and `{{ value | default(null) }}` treat these as PHP literals, not variable names.

Tests
-----

[](#tests)

See [TESTS.md](TESTS.md) for the full test suite results covering output, escaping, conditionals, loops, filters, tags, includes, inheritance, literals, and security.

License
-------

[](#license)

MIT

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance84

Actively maintained with recent releases

Popularity4

Limited adoption so far

Community10

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Total

3

Last Release

82d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3036663?v=4)[Mike W](/maintainers/enlivenapp)[@enlivenapp](https://github.com/enlivenapp)

---

Top Contributors

[![enlivenapp](https://avatars.githubusercontent.com/u/3036663?v=4)](https://github.com/enlivenapp "enlivenapp (3 commits)")

### Embed Badge

![Health badge](/badges/enlivenapp-vision/health.svg)

```
[![Health](https://phpackages.com/badges/enlivenapp-vision/health.svg)](https://phpackages.com/packages/enlivenapp-vision)
```

###  Alternatives

[limenius/react-bundle

Client and Server-side react rendering in a Symfony Bundle

3851.2M](/packages/limenius-react-bundle)[webkinder/sproutset

A Composer package for handling responsive images in Roots Bedrock + Sage + Blade projects.

282.2k](/packages/webkinder-sproutset)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
