PHPackages                             michel/pure-plate - 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. michel/pure-plate

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

michel/pure-plate
=================

PurePlate is a lightweight and versatile template rendering library for native PHP.

1.0.0(8mo ago)016MITPHPPHP &gt;=7.4

Since Dec 16Pushed 3mo agoCompare

[ Source](https://github.com/michelphp/pure-plate)[ Packagist](https://packagist.org/packages/michel/pure-plate)[ RSS](/packages/michel-pure-plate/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (4)Dependencies (1)Versions (5)Used By (0)

PurePlate
=========

[](#pureplate)

**A lightweight template engine for PHP. The syntax of Jinja. The power of native PHP. None of the weight.**

PurePlate parses templates with PHP's native `token_get_all()` lexer and compiles them to plain, cached PHP. No runtime overhead. No bloat. No magic.

```
{% extends "layout.tpl" %}

{% block content %}
    Hello, {{ user.name|upper }}!

    {% if items is not empty %}

        {% foreach items as item %}
            {{ item.title }} — {{ item.price|number_format(2, ',', ' ') }} €
        {% endforeach %}

    {% endif %}
{% endblock %}
```

---

Why PurePlate
-------------

[](#why-pureplate)

### 1. Any PHP function works as a filter — out of the box

[](#1-any-php-function-works-as-a-filter--out-of-the-box)

In Twig, every filter must be registered:

```
// Twig: you have to declare each function as a filter
$twig->addFilter(new TwigFilter('upper', 'strtoupper'));
$twig->addFilter(new TwigFilter('format', 'number_format'));
```

In PurePlate, every PHP function is already a filter:

```
{{ name|strtoupper }}
{{ price|number_format(2, ',', ' ') }}
{{ text|substr(0, 100) }}
{{ items|count }}
{{ date|date("Y-m-d") }}
```

No registration. No wrappers. The entire PHP standard library is available immediately.

### 2. Lexer-based, not regex-based

[](#2-lexer-based-not-regex-based)

Templates are tokenized with PHP's own `token_get_all()` — the same lexer PHP uses to parse its own source code. This means:

- Correct handling of strings, escapes, nested quotes
- No regex edge-cases that break on unusual input
- Predictable, deterministic parsing

### 3. Compile-time validation

[](#3-compile-time-validation)

Generated PHP is validated with `TOKEN_PARSE` **before** being cached. If the compilation produces invalid PHP, you know immediately — not at runtime, not in production.

### 4. Source-mapped errors

[](#4-source-mapped-errors)

Every compiled line carries a comment pointing back to the original template:

```

```

When an error happens, PurePlate rewrites the exception to point at the **template file and line**, not the cached PHP file.

```
PurePlate Error: Undefined variable $username [At: templates/page.tpl:14]

```

### 5. Auto-escaping by default

[](#5-auto-escaping-by-default)

`{{ var }}` is always passed through `htmlspecialchars(..., ENT_QUOTES)`. Output is safe by default.

---

Comparison
----------

[](#comparison)

Twig 3PurePlateSyntaxTwigTwig-likePHP function as filter❌ Must register✅ NativeCompile-time syntax check❌✅Source-mapped errors⚠️ Complex✅ InlinePHP 7.4 support⚠️ Twig 3.x only✅DependenciesSeveralZeroAuto-escape✅✅---

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

[](#installation)

```
composer require michel/pure-plate
```

PHP 7.4 or higher. No other runtime dependencies.

---

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

[](#quick-start)

```
use Michel\PurePlate\Engine;

$plate = new Engine(__DIR__ . '/templates');

echo $plate->render('page.tpl', [
    'user'  => ['name' => 'fady'],
    'items' => [
        ['title' => 'Item A', 'price' => 19.90],
        ['title' => 'Item B', 'price' => 42.00],
    ],
]);
```

---

Syntax
------

[](#syntax)

### Output

[](#output)

```
{{ variable }}                       {# auto-escaped #}
{{ user.name }}                      {# same as user->name #}
{{ user.getName() }}                 {# method call #}
{{ value|filter }}                   {# any PHP function #}
{{ value|filter(arg1, arg2) }}       {# with arguments #}
```

### Control structures

[](#control-structures)

```
{% if condition %} ... {% elseif other %} ... {% else %} ... {% endif %}
{% foreach items as item %} ... {% endforeach %}
{% for i = 0; i < 10; i++ %} ... {% endfor %}
{% while condition %} ... {% endwhile %}
```

### Tests

[](#tests)

```
{% if list is empty %} ... {% endif %}
{% if list is not empty %} ... {% endif %}
{% if not active %} ... {% endif %}
```

### Variable assignment

[](#variable-assignment)

```
{% set total = price * quantity %}
```

### Template inheritance

[](#template-inheritance)

```
{# layout.tpl #}

    {% block content %}{% endblock %}

{# page.tpl #}
{% extends "layout.tpl" %}
{% block content %}
    Hello
{% endblock %}
```

### Includes

[](#includes)

```
{% include "partials/header.tpl" %}
```

### Comments

[](#comments)

```
{# This will not appear in the output #}
```

---

Dev mode
--------

[](#dev-mode)

In dev mode, templates are recompiled on every request:

```
$plate = new Engine(__DIR__ . '/templates', devMode: true);
```

In production (default), templates are compiled once and cached. The cache is invalidated automatically when the template source changes.

---

Cache directory
---------------

[](#cache-directory)

By default, compiled templates are stored in the system temp directory. To customize:

```
$plate = new Engine(
    templateDir: __DIR__ . '/templates',
    devMode: false,
    cacheDir: __DIR__ . '/var/cache/plate'
);
```

---

Globals
-------

[](#globals)

Variables passed as globals are available in every template without being re-passed at each render:

```
$plate = new Engine(__DIR__ . '/templates', globals: [
    'siteTitle' => 'My Site',
    'version'   => '1.0',
]);
```

---

License
-------

[](#license)

Mozilla Public License 2.0

###  Health Score

32

—

LowBetter than 69% of packages

Maintenance73

Regular maintenance activity

Popularity6

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity38

Early-stage or recently created project

 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 ~28 days

Total

4

Last Release

159d ago

Major Versions

1.0.0 → 2.0.0-alpha2026-03-09

### Community

Maintainers

![](https://www.gravatar.com/avatar/909a078010ad44ff35146af8288451a3b6fd26f81cb198cbea776a92553c9b8a?d=identicon)[F.Michel](/maintainers/F.Michel)

---

Top Contributors

[![michelphp](https://avatars.githubusercontent.com/u/26349908?v=4)](https://github.com/michelphp "michelphp (10 commits)")

---

Tags

phpphp-template-enginetemplatetwig-alternative

### Embed Badge

![Health badge](/badges/michel-pure-plate/health.svg)

```
[![Health](https://phpackages.com/badges/michel-pure-plate/health.svg)](https://phpackages.com/packages/michel-pure-plate)
```

###  Alternatives

[limenius/react-bundle

Client and Server-side react rendering in a Symfony Bundle

3841.2M](/packages/limenius-react-bundle)[pdewit/nova-external-url

An external URL Laravel Nova field.

30383.2k](/packages/pdewit-nova-external-url)[wbrowar/guide

A CMS Guide for Craft CMS.

6154.7k1](/packages/wbrowar-guide)

PHPackages © 2026

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