PHPackages                             wackowiki/templatest - 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. wackowiki/templatest

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

wackowiki/templatest
====================

Push-style, lazy, topo-ordered incremental template engine for WackoWiki

0.9(today)13↑2900%BSD-3-ClausePHPPHP &gt;=8.3

Since Aug 25Pushed todayCompare

[ Source](https://github.com/WackoWiki/Templatest)[ Packagist](https://packagist.org/packages/wackowiki/templatest)[ RSS](/packages/wackowiki-templatest/feed)WikiDiscussions main Synced today

READMEChangelogDependencies (1)Versions (2)Used By (0)

Templatest
==========

[](#templatest)

> Push-style (with pull methods for e.g. csrf &amp; i18n) lazy topo-ordered incremental building, liberated from von-neumann-style applicative transition template engine for WackoWiki.

Templatest is a lightweight, compiled template engine that separates presentation from logic. Templates are compiled once into an internal AST of *patterns*, *variables*, *subpatterns* and *filters*, then rendered by walking the AST and applying transformations on demand.

Features
--------

[](#features)

- **Compiled templates** — parsed once, cached to disk, reused across requests
- **Pattern blocks** — define and recall named sections (`[= name =] ... [=]`)
- **One-off pattern definitions** — `[= abc def = ... =]` for inline sub-templates
- **Variables** — `[' var ']` with optional filter pipes (`| upper | default "anon"`)
- **Subpatterns** — `[ ' name ' ]` to embed pattern instances
- **Pull actions** — `[ '' name: arg1 '' ]` to call user-supplied functions at render time
- **Filter pipeline** — built-in filters for HTML/JS/CSS/URL escaping, string manipulation, dates, numbers, JSON encoding, and more
- **Auto-indent** — block tags automatically align with their surrounding context
- **Pre-block support** — special handling for `` and `` content
- **Escaper** — context-aware escaping (HTML, HTML attribute, JS, CSS, URL) based on Zend Framework
- **Pull-style extensibility** — register runtime callbacks (CSRF tokens, i18n, etc.) that the template can invoke
- **PHP 8.1+ strict typing** — fully typed, namespaced, framework-independent
- **No dependencies** — zero Composer runtime dependencies; PHPUnit only for dev

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

[](#requirements)

- PHP **8.1** or later
- `iconv` or `mbstring` extension (for non-UTF-8 encoding support in `TemplatestEscaper`)

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

[](#installation)

```
composer require templatest/templatest
```

Or, if vendoring manually:

```
require __DIR__ . '/vendor/autoload.php';
```

Quick start
-----------

[](#quick-start)

### Template file `hello.tpl`

[](#template-file-hellotpl)

```
[= hello =]

[ ' title ' ]

Hello, [ ' name ' ]!
[ ' items ' ]

[= items =]

[ ' item ' ]

[=]

[= item =]
[ ' text ' ]
[=]

```

(Use `[==== name ====]` for visual emphasis — Templatest accepts any number of `=` signs.)

### Rendering

[](#rendering)

```
use Templatest\Templatest;

$tpl = Templatest::read('hello.tpl', '/path/to/cache');

$tpl->title         = 'My Page';
$tpl->name          = 'World';
$tpl->items_item_text = 'first';   // underscore-split path: items → item → text
$tpl->items_item_text = 'second';  // second iteration of same pattern

echo $tpl;
```

### Output

[](#output)

```
>

My Page

Hello, World!

first
second

```

Template syntax
---------------

[](#template-syntax)

### Quote convention

[](#quote-convention)

Templatest tags are wrapped in `'` (apostrophe) characters. You can use **one or more**quotes on each side — the parser treats them as visual delimiters only. The minimum is one:

```
[' var ']              ← one quote (recommended)
['' var '']            ← two quotes (works, no functional difference)
[''' var ''']          ← three quotes (works, but visually noisy)

```

For nesting clarity, it's common to use **more quotes for outer context** and **fewer for inner context**, though this is purely cosmetic:

```
[ '' pull_function: [' inner_var '] '' ]   ← pull with inner variable

```

### Equal signs in pattern markers

[](#equal-signs-in-pattern-markers)

Pattern blocks use `[= name =]` or `[==== name ====]` — any number of `=` signs works:

```
[= main =]
[==== main ====]
[================ main =================]

```

All three are equivalent. Use whichever reads best.

### Pattern definition

[](#pattern-definition)

```
[= pattern_name =]
... template body ...
[=]

```

The first pattern defined in a file is the **main** pattern and is the one rendered by default.

### Inline (one-off) pattern

[](#inline-one-off-pattern)

```
[= anon = ...inline body... =]

```

Useful for small reusable chunks. The name may be a single punctuation character (anonymous) or an identifier.

### Variables

[](#variables)

```
[' var_name ']
[' var_name | filter1 | filter2 ']

```

Variables are assigned from PHP via `$tpl->var_name = 'value'` or via underscore-split paths.

### Subpatterns

[](#subpatterns)

```
[ ' sub_pattern ' ]
[ ' my_name sub_pattern ' ]

```

Embeds a pattern instance. Each invocation instantiates a fresh copy unless static inlining applies.

### Pull actions

[](#pull-actions)

```
[ '' function_name '' ]
[ '' function_name: arg1 arg2 '' ]

```

Invokes a user-registered PHP callback. The callback receives:

```
function my_pull(bool $is_block, string $loc, ...$args): string
```

### Filter pipes

[](#filter-pipes)

```
[' msg | upper | trim ']
[' msg | default "anonymous" | escape ']

```

Filters are evaluated left-to-right. The result of each filter is the input to the next.

### Setup directives

[](#setup-directives)

```
.escape html                    # default escape mode for this file
.escape html pattern_name       # escape mode for a specific pattern
.patch patname varname value    # pre-populate a variable in a pattern
.include other_template.tpl     # include another template file

```

Built-in filters
----------------

[](#built-in-filters)

FilterAliasDescription`escape``e`HTML-escape value (modes: `html`, `js`, `css`, `url`, `html_attr`, `raw`)`default`Use fallback when value is null/false`format``sprintf()` the value`stringify`Convert any value to a readable string`date`Format a Unix timestamp`join`Implode an array with a glue`lower``mb_strtolower``upper``mb_strtoupper``number``number_format` with custom decimal/thousands separators`void`Drop the value (returns null)`index`Drill into nested arrays via dot-notation path (or `var.path` sugar)`replace`Sequential `str_replace` pairs`json_encode`Encode value as JSON, optional flags`json_decode`Decode JSON string`sp2nbsp`Convert runs of spaces to non-breaking spaces`spaceless`Strip whitespace between HTML tags (preserves ``, ``)`regex``preg_replace`; strict mode returns null on no match`trim``trim` with custom character mask`url_encode`URL-encode a scalar or encode an array as query string`striptags`Strip HTML tags with optional allow-list`nl2br`Convert double newlines to `` blocks`truncate`Truncate to a length with ellipsis`split`Explode or `str_split` depending on delimiter`list`Pick one of N arguments by index`enclose`Wrap with prefix and postfix strings`check`Render a checkbox `` value/checked pair`checkbox`Render `checked` attribute if truthy`select`Render `selected` attribute if matches`pre`Mark next output as preformatted (no auto-indent)API reference
-------------

[](#api-reference)

### `Templatest::read(string $filename, ?string $cache_dir = null): TemplatestUser`

[](#templatestreadstring-filename-string-cache_dir--null-templatestuser)

Compiles (or loads from cache) the template and returns a renderable instance.

- **`$filename`** — path to the template file
- **`$cache_dir`** — optional directory for cached compiled templates

```
$tpl = Templatest::read('page.tpl', __DIR__ . '/cache');
```

### `TemplatestUser`

[](#templatestuser)

#### Magic `__set`

[](#magic-__set)

```
$tpl->name = 'Alice';              // set top-level variable
$tpl->user_name = 'Alice';         // underscore-split: 'user' → 'name'
```

The single-segment form (`$tpl->name = ...`) sets a top-level variable. The underscore form walks the pattern tree, so `$tpl->items_item_text` is equivalent to `$tpl->set('items', 'item', 'text', value)`.

#### Magic `__get`

[](#magic-__get)

```
$count = (int) $tpl->name;         // number of times 'name' was set
```

Returns the set-count for the chroot-prefixed variable name. **Returns `int`, not an object** — chained property access (`$tpl->items->item->text`) does NOT work; use the underscore-split form for both reading and writing.

#### Chroot context

[](#chroot-context)

```
$tpl->enter('user_');              // push context — variable names get 'user_' prefix
$tpl->name = 'Alice';              // → 'user_name'
$tpl->age  = 30;                   // → 'user_age'
$tpl->leave();                     // pop context
```

#### Pull functions

[](#pull-functions)

```
$tpl->pull('csrf', function (bool $is_block, string $loc) {
    return '';
});
```

#### Clone by pattern name

[](#clone-by-pattern-name)

```
$header = $tpl->header;           // clones the template rooted at pattern 'header'
$header->title = 'Welcome';
echo $header;                     // renders only the header pattern
```

#### Direct invocation

[](#direct-invocation)

```
$tpl('name', 'Alice', 'age', 30);  // equivalent to $tpl->set('name', 'Alice', 'age', 30)
```

#### `set()`

[](#set)

```
$tpl->set('name', 'Alice');                        // underscore-split path
$tpl->set(['name' => 'Alice', 'age' => 30]);       // array form
$tpl->set('user', 'name', 'Alice');                // explicit nested path
```

### `TemplatestEscaper`

[](#templatestescaper)

Context-aware escaping utilities, exposed via the `escape` filter:

```
$escaper = new TemplatestEscaper();
echo $escaper->escape_html('x');    // &lt;b&gt;x&lt;/b&gt;
echo $escaper->escape_js("'");             // \x27
echo $escaper->escape_url('hello world');  // hello%20world
```

Caching
-------

[](#caching)

Compiled templates are cached to disk if a `$cache_dir` is provided. The cache is invalidated when:

- the source file's `mtime` changes
- the cache file is missing or unreadable
- the cache file's `CODE_VERSION` doesn't match the running version

To disable caching for a single file, set its write bit off (`chmod 644`); Templatest will re-read from source each time.

To clear the entire cache:

```
rm -rf /path/to/cache/*
```

Configuration
-------------

[](#configuration)

### Setup directives (in `.tpl` files)

[](#setup-directives-in-tpl-files)

```
.escape html                  # default escape mode (default: raw)
.escape html pattern_name     # escape mode for a specific pattern
.patch main title "Welcome"   # pre-set variable 'title' to "Welcome" in pattern 'main'
.include header.tpl           # include another template file

```

### Default escape modes

[](#default-escape-modes)

`TemplatestSetter::ESCAPER` constant controls the default when a pattern has no explicit `.escape` directive. Default is `'raw'` (no escaping).

Testing
-------

[](#testing)

```
composer install
vendor/bin/phpunit
```

Run with testdox formatting:

```
vendor/bin/phpunit --testdox
```

Run a single test:

```
vendor/bin/phpunit --filter test_random_token
```

Generate coverage (requires `pcov` or `xdebug`):

```
composer require --dev pcov/clobber
vendor/bin/phpunit --coverage-html coverage/
```

Architecture
------------

[](#architecture)

```
src/
├── Templatest.php         # compiler entry point; reads & caches templates
├── TemplatestUser.php     # public API; per-instance renderable
├── TemplatestSetter.php   # assigns values into chunks; runs filter pipes
├── TemplatestFilters.php  # built-in filter registry
├── TemplatestEscaper.php  # context-aware string escaping (Zend-derived)
├── Helper.php             # standalone utilities (path, serialize, stringify, etc.)
└── Exception/
    ├── InvalidArgumentException.php
    └── RuntimeException.php

```

### Compilation pipeline

[](#compilation-pipeline)

```
.tpl source
   │
   ▼
parse_file()         ─── reads file, splits into patterns, processes .include / .escape / .patch
   │
   ▼
inline_definitions() ─── extracts inline [= abc def = ... =] blocks
   │
   ▼
compile()            ─── scans each pattern for [' ... '] tags,
                        builds chunks + var/sub/pull metadata
   │
   ▼
inline_static_subs() ─── inlines subpatterns that have no dynamic content
   │
   ▼
inline_defaults()    ─── applies [' x | default "..." '] defaults
   │
   ▼
cache → TemplatestUser instance

```

### Render pipeline

[](#render-pipeline)

```
$tpl = Templatest::read('page.tpl');
$tpl->title = 'Hello';
echo $tpl;    // __toString() → commit(root)
                  ├── iterate pull actions
                  ├── recurse into subpatterns
                  └── implode chunks

```

Standalone helper utilities (`Helper` class)
--------------------------------------------

[](#standalone-helper-utilities-helper-class)

Methods used internally that may also be useful on their own:

- `Helper::join_path(...$parts): string|false`
- `Helper::serialize_data($data, $options = 0): string`
- `Helper::unserialize_data($text): mixed`
- `Helper::http64_encode($data): string`
- `Helper::is_empty($val): bool`
- `Helper::random_token($length = 10, $complexity = 2): string`
- `Helper::str_rand($min, $max): int`
- `Helper::qencode($name, $value): string`
- `Helper::stringify($x, $compact = 0, $full = 1): string|false`
- `Helper::dbg(...$args): void`
- `Helper::callee($class_filter): string`

Credits
-------

[](#credits)

- Original WackoWiki templating engine by the WackoWiki team
- HTML escaper adapted from the BSD-licensed Zend Framework
- Standalone port and namespace cleanup by the Templatest maintainers

License
-------

[](#license)

BSD-3-Clause — see `LICENSE` file.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance100

Actively maintained with recent releases

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

Unknown

Total

1

Last Release

0d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/54716082?v=4)[vendeeglobe](/maintainers/vendeeglobe)[@vendeeglobe](https://github.com/vendeeglobe)

---

Top Contributors

[![vendeeglobe](https://avatars.githubusercontent.com/u/54716082?v=4)](https://github.com/vendeeglobe "vendeeglobe (2 commits)")

---

Tags

phptemplatingtemplating-enginetemplatingwikiwackowiki

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/wackowiki-templatest/health.svg)

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

###  Alternatives

[twig/twig

Twig, the flexible, fast, and secure template language for PHP

8.4k473.8M7.8k](/packages/twig-twig)[mustache/mustache

A Mustache implementation in PHP.

3.3k48.6M333](/packages/mustache-mustache)[smarty/smarty

Smarty - the compiling PHP template engine

2.3k42.7M494](/packages/smarty-smarty)[timber/timber

Create WordPress themes with beautiful OOP code and the Twig Template Engine

5.7k3.8M145](/packages/timber-timber)[league/plates

Plates, the native PHP template system that's fast, easy to use and easy to extend.

2.1k6.3M297](/packages/league-plates)[eftec/bladeone

The standalone version Blade Template Engine from Laravel in a single php file

82910.1M126](/packages/eftec-bladeone)

PHPackages © 2026

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