PHPackages                             php-templates/php-templates - 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. php-templates/php-templates

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

php-templates/php-templates
===========================

Php templating engine

2.0(2y ago)6432MITPHP

Since Oct 23Pushed 1y ago1 watchersCompare

[ Source](https://github.com/php-templates/php-templates)[ Packagist](https://packagist.org/packages/php-templates/php-templates)[ Docs](https://github.com/php-templates/php-templates)[ RSS](/packages/php-templates-php-templates/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (10)Dependencies (2)Versions (13)Used By (2)

***Php-Templates*** is a template engine which goal is to bring full modularity into 'View' part of a web app. Unlike some PHP templating engines, ***Php-Templates*** does not restrict you from using plain PHP code and functions in your templates as a 'measure of security'. It gives you the freedom to organizes your templates as you wish. In fact, all templates are compiled into plain PHP code and cached until they are modified, meaning ***Php-Templates*** adds essentially zero overhead to your application, also it has a clear syntax due to the fact that control structures are placed as targeted tag attribute.

Setting up
----------

[](#setting-up)

`composer require php-templates/php-templates`or just include `autoload.php` file in your script.

View files will have the `.t.php` extension and be placed in configured source path. They will be refered by their relative name, without extension and without source path prepended.

```
 true]);
$cfg = $viewFactory->getConfig();

$view = $viewFactory->makeRaw('Hello {{ $world }}', ['world' => 'Php Templates']);
$view->render();

```

```

Hello Php Templates

```

Data interpolation
------------------

[](#data-interpolation)

Like in most template engines, data is escaped against html entities and displayed using `{{ $var }}` syntax. You can use `{!! $var !!}` syntax in order to display raw, unescaped data. The following:

`// examples/hello.t.php`

```
{{ $h1 }}

```

```
$viewFactory->make('examples/hello', ["h1" => "Hello Php Templates"])->render();

```

will result:

```
Hello Php Templates

```

Unlike other template engines, interpolation is resumed only on text nodes. The following syntax won't work:

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', ["value" => "No value"])->render();

```

will result:

```

```

In order to bind values to node attributes, just write your attributes prefixed by ':'. We will further refer this syntax as 'bind'.

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', ["value" => "No value"])->render();

```

will result:

```

```

In fact, the syntax above will be translated to `value=""`, means you can replace `$value` with any valid php syntax.

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', ["value" => "No value"])->render();

```

will result:

```

```

Class attribute is a special case, because we often have many of them, or we need to conditionate some of them. You can:

- give an array of values, ex: `:class="['class1', true ? 'class2' : '']"` and expect as result `class="class1 class2"`
- give an associative array where keys are attribute values and values are filter criteria, ex: `:class="['class3' => 1, 'class4' => 0]"` will result `class="class3"`; Classes are cumulative, so having many attributes of them, will concatenate their values into a single class atrribute.

Php syntax
----------

[](#php-syntax)

In order to cover other features and to avoid any ambiguosity in parse process, template files are loaded using php 'require'. This means you cannot use php tags for declaring render time stuffs, like variables, function calls, etc. Instead, you can use `{% ... %}` tags, or single line tags `{% ... %}`

`// examples/hello.t.php`

```
{% $text = 'Lorem ipsum'; %}
{% $name = 'fname'; %}

```

```
$viewFactory->make('examples/hello', [])->render();

```

will result:

```

```

If you wonder how then conditionally rendering attributes is possible, take a look at 'Directives' section. First, we have to cover control structures.

Control structures
------------------

[](#control-structures)

Allowed control structures are: `if, elseif, else, foreach`You can use them to conditionally render a node. Just add them as attribute on targeted node, prefixed with `p-`.

`// examples/hello.t.php`

```
{% $inp = ['text', 'number', 'email']; %}

{{ $value }}

```

```
$viewFactory->make('examples/hello', ['type' => 'textarea', 'value' => 'Lorem'])->render();

```

will result:

```
Lorem

```

Here is a `foreach` example:

`// examples/hello.t.php`

```
Do you like Php Templates?

   {{ $lbl }}

```

```
$viewFactory->make('examples/hello', ['options' => ['1' => 'Yes', '0' => 'No']])->render();

```

will result:

```
Do you like Php Templates?

      Yes
      No

```

In Php Templates, loops are scoped, meaning that anything declared inside a loop, will stay in the loop and not be available outside of it. Also, anything from outside of the loop can't be overriden from inside the loop. In the above example, in a normal php script, `$lbl` and `$val` would be available below the loop. Not in this case:

`// examples/hello.t.php`

```
{% $lbl = 'I will survive!!!'; %}

   {{ $lbl }}

{{ $lbl . $val }}

```

```
$viewFactory->make('examples/hello', ['options' => ['1' => 'Yes', '0' => 'No']])->render();

```

will result:

```

      Yes
      No

I will survive!!!

```

Directives
----------

[](#directives)

Directives are 'parsing phase' commands and are usefull when you need to declare complex logic under a small alias. They are node attributes prefixed with 'p-', like control structures.

### Built-in directives

[](#built-in-directives)

`raw` - usefull when you need to conditionally render content on a tag declaration:

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', ["condition" => true])->render();

```

will result:

```

```

Please note that is IMPORTANT to escape nested quotes using backslash. Or just avoid it by using next directive (`bind`). Using this directive on a component node will take no effect.

`bind` - declare node attributes inside an associative array. This is usefull if you need to conditionate rendering of some specific attributes.

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', ["attrs" => [ "type" => "text", "name" => "name", "disabled"] ])->render();

```

will result:

```

```

As a matter of rendering performance, the limitation is that you cannot `bind` class attribute, or any attribute already declared on node.

`checked` - used on input type radio / checkbox

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', ["theradio" => 1])->render();

```

will result:

```

```

`selected` - used on select input

`// examples/hello.t.php`

```

    {{ $label }}

```

```
$viewFactory->make('examples/hello', ["options" => ["a" => "avocado", "b" => "banana", "c" => "cherry"], "value" => "b"])->render();

```

will result:

```

      avocado
      banana
      cherry

```

`disabled` - used to apply attribute `disabled`

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', [])->render();

```

will result:

```

```

### Custom directives

[](#custom-directives)

Directives are dispatched before any node attribute be parsed. So, basically, they are populating the DomNode with attributes which becomes parsed. You can declare your own custom directives like this:

```
$cfg->setDirective('guest', function($node, $val) {
    $node->addAttribute('p-if', 'empty($user)');
});
$cfg->setDirective('auth', function($node, $val) {
    $node->addAttribute('p-if', '!empty($user)');
});
$cfg->setDirective('active', function($node, $val) {
    $node->addAttribute(':class', "$val ? 'active' : ''");
});

```

Now, the following:

`// examples/hello.t.php`

```
Guest
Auth

```

```
$viewFactory->make('examples/hello', [])->render();

```

will result:

```
Guest
Auth

```

Note that `$val` param passed to callback function is the string value of the directive attribute, in our case `3 < 4`. You can learn more about DomNode manipulation at Working with DOM section.

Entities
--------

[](#entities)

### Components

[](#components)

You can reuse parts of design by making them components. Just put the html code into another file in your source path in any folder structure you preffer. For example, you can have: // components/form-group.t.php

```
{%
$_attrs = $_context->except(['label','class']); // this will take any passed attribute not in listed array
%}

    {{ $label }}

        {{ $label }}

        {{ $label }}

        {{ $label }}

    {{ $value }}
    {{ $error }}

```

and use it like this:

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', [ "label" => "The Label", "value" => "The Value" ])->render();

```

will result:

```

    The Label

```

Components will have their own scope (no access to upper context of values) so you have to irrigate them with data. You can pass values to componenent context in 3 ways:

- simple attribute: will be passed as string value, ex.: `value="somevalue"`
- bind syntax: php syntax accepted, ex.: `:value="$value"`, or `:value="'The value'"`
- bind attribute: using `p-bind` directive, which accepts an array of attributes You can also have control structures on components nodes. When working with multiple namespaces configs (`$viewFactory->subConfig($name='cfg2', $sourcePath)`) and your has a component with same name, for example `form-group`:
- form-group
- cfg2:form-group
- cfg2:some-file If you refer `form-group` in `cfg2:some-file`, you will get default one. You can instruct php-templates that you want local config template like this ` 'components/form-group',
]);

```

Now, we can use our component:

```
instead of this

like this

```

!!! Disclaimer: ***Php-Templates*** won't protect you against infinite reccursivity, so avoid aliasing components to valid html tags like `` component having another section as body tag.

### Slots

[](#slots)

Slots increases a component reusability by leting us to control a defined layout from outside. Slots may have default content as child node, which will be rendered when no slot defined. Slots may be named, or default. Slots are sub-scoped:

- compiled outside the component in which they are passed
- having access to variables declared in this 'outside' scope, but cannot modify them Considering our form-group component with slots would be: components/form-group.t.php

```

        {{ $label }}

            {{ $label }}

            {{ $label }}

            {{ $label }}

        {{ $value }}

    {{ $error }}

```

Now, we can use it like this:

`// examples/hello.t.php`

```

    Custom label

```

```
$viewFactory->make('examples/hello', [])->render();

```

will result:

```

  Custom label

```

No slot is required to be passed. Empty slots will render nothing and slots with default values (declared between `` tag) will evaluate that value. Multiple nodes can fill the same slot name.

#### Scoped Slots Data

[](#scoped-slots-data)

Consider you have a component responsable for rendering a table: //components/data-table.t.php

```

            {{ $heading }}
            Action

                {{ $item[$k] }}

```

Two things here:

- we checked if any slot passed by calling `$this->slots($slotName)`
- we passed some data on slot node declaration ($id and $i), then we can access this values outside component, like this `$slot->varName`Now, we can use the component like this:

`// examples/hello.t.php`

```

        Edit

```

```
$viewFactory->make('examples/hello', [
'headings' => [
    'id' => 'ID',
    'name' => 'Name'
],
'data' => [
    ['id' => 67, 'name' => 'Mango'],
    ['id' => 32, 'name' => 'Potatos'],
]])->render();

```

will result:

```

              ID
              Name
              Action

                      67
                      Mango

  Edit

                      32
                      Potatos

  Edit

```

Extends
-------

[](#extends)

Consider we have a main layout: // layouts/app.t.php

```

    …

        … {{ $var }}

```

Now, we can have all our templates extending it, like this:

`// examples/hello.t.php`

```

    … {{ $var }}

```

```
$viewFactory->make('examples/hello', ['var' => 'I am shared with my parent'])->render();

```

will result:

```

  …

        … I am shared with my parent… I am shared with my parent

```

As you can see, extended template shares the same context with the child, means it can have access to child variables/child automatically binds variables to parent.

Global Shared data
------------------

[](#global-shared-data)

You can use the following method on TemplateFactory instance to share a value across all templates (nested, extended, components or not) built by it:

```
share('shared', 'I share because I care');

```

`// examples/hello.t.php`

```
… {{ $shared }}

```

```
$viewFactory->make('examples/hello', [])->render();

```

will result:

```
… I share because I care

```

Shared data have low precedence, meaning they are there, only if they are not overriden by another value with the same label (variable name).

Composing data
--------------

[](#composing-data)

You may have pieces of UI in your app which may repeat on different pages and you may feel tired of building the data for each one. Here is a filtered list: // components/filtered-list.t.php

```

    {{ $item }}

```

then we register a composer:

```
composer('components/filtered-list', function($attrs) {
    $fruits = ['avocado', 'banana', 'cherry', 'berry'];
    // you can have sql here too
    if ($attrs->sort == 'DESC') {
        rsort($fruits);
    }
    elseif ($attrs->sort == 'ASC') {
        sort($fruits);
    }
    $attrs->items = $fruits;
});

```

now, calling our component like this:

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', [])->render();

```

will result:

```

      avocado
      banana
      berry
      cherry

      cherry
      berry
      banana
      avocado

```

Events
------

[](#events)

Each template is transformed into a virtual DOM then semantically parsed from top to bottom, entering in each child node. This empowers Php Templates with ability to intervents in parsing process and manipulate DOM in a close to JavaScript flexibility (add, remove, edit node). There are three ways of doing this:

### Parsing moment

[](#parsing-moment)

We have our form: form.t.php

```

```

Now we add an event listener:

```
$viewFactory->on('parsing', 'form', function($node) {
    // any css selector here
    $node->querySelector('form')
    ->appendChild('');
    $city = $node->querySelector('form [name="city"]');
    $node->querySelector('form')
    ->insertBefore('', $city);
    $city->detach();
    // see Working with DOM section for more details
});

```

and when we call our template (direct, or nested): $viewFactory-&gt;render('form', \[\]);

```
Firstname

```

```
Lastname

```

```
Age

```

```
Zipcode

  Because of cache system, parsing events are impossible to be tracked for changes to recompile the code. You have to reset them manually by deleting cached files, or better, pass null as cache path on Template instancing. This will parse templates on each request without caching them (do this only during development).

```

### On Rendering time

[](#on-rendering-time)

Let it be our last sorted list:

```

```

add event

```
$viewFactory->on('rendering', 'components/filtered-list', function($context) {
    $context->items[] = 'added';
});

```

and the call:

`// examples/hello.t.php`

```

```

```
$viewFactory->make('examples/hello', [])->render();

```

will result:

```

      avocado
      banana
      berry
      cherry
      added

```

pretty usefull if you want to add data on fly

### Self events

[](#self-events)

When you declare a template which will suppose to be a component, you may return a php function which will be called as callback before template parse. This feature is usefull if you have components which have script/css/cdn dependencies and you want to keep them grouped together. We may have our form group to accept images with preview:

```

        {{ $label ?? $name ?? '' }}

            ...

        {{ $error }}

$(document).on("change", 'input[type="file"].preview', function() {
    const [file] = this.files
    if (file) {
       $(this).prev("img").attr("src", URL.createObjectURL(file));
    }
});

querySelector('#moveMe')->detach()->removeAttribute('id');
    $eventHolder->on('parsed', 'layouts/*', function($node) use ($script) {
        $node->querySelector('head')->appendChild($script);
    });
} ?\>

```

Events may be declared eliptic in name using \*, (meaning anything except '/'). Events declaration may accept a weight as 4'th argument which will define listener execution order (high to low). In the above example, we needed to detach the $script and keep a reference of it, because in event callback would be too late because the component would be already transformed to template function at that point and any change made would take no effect. Also, layout rendering event was triggered before this point.

DomNode and Dom manipulation
============================

[](#domnode-and-dom-manipulation)

PhpTemplates parses every template into a virtual dom, then reccursively traverse each node to handle semantic syntaxes/nodes. At the end, the dom is saved into a valid tpl format. This makes PhpTemplates different from other template engines. You can hook anywhere in the dom and insert whatever element you want, modify or delete dom elements. Each node is a DomNode object class. We will list below the class methods you can use.

### `__construct(string $nodeName, $nodeValue = '')`

[](#__constructstring-nodename-nodevalue--)

Constructs a DomNode instance, like div, span, etc. $nodeName - tag name. In case of textnode, prefix `$nodeName` with '#' and name it as you wish $nodeValue - if textnode, it should be string. If domNode, it can be a key =&gt; value array containing attributes (ex: \['class' =&gt; 'foo bar'\])

### static `fromString(string $str)`

[](#static-fromstringstring-str)

Create a new DOM structure from a given string, ex: `Hello World`This fn will try to capture its call location in order to give relevant data for debugging

### `addAttribute($nodeName, string $nodeValue = '')`

[](#addattributenodename-string-nodevalue--)

Add an attribute to node in append mode (if an attribute class exists on node and you call `addAttribute('class', 'class2')`, it will add this class too) $nodeName - string|DomNodeAttr $nodeValue - string

### `setAttribute(string $nodeName, string $nodeValue = '')`

[](#setattributestring-nodename-string-nodevalue--)

Add an attribute to node. If an already existing attribute will be found by given name, its value will be overriden

### `getAttribute(string $name)`

[](#getattributestring-name)

Returns node attribute value by attribute name, null if no attribute found

### `hasAttribute(string $name)`

[](#hasattributestring-name)

Determine if an attribute exists on current node, by its name

### `removeAttribute(string $name): self`

[](#removeattributestring-name-self)

Remove node attribute, return node instance

### `removeAttributes()`

[](#removeattributes)

Remove all node attributes

### `appendChild($node)`

[](#appendchildnode)

Append a new child node to current node and returns appended child instance. If appended node already exists in this node flow, it will throw an error to prevent infinite recursion

### `insertBefore($node, self $refNode)`

[](#insertbeforenode-self-refnode)

Insert a child node before another given childnode If appended node already exists in this node flow, it will throw an error to prevent infinite recursion

### `insertAfter($node, self $refNode)`

[](#insertafternode-self-refnode)

Insert a child node after another given childnode If appended node already exists in this node flow, it will throw an error to prevent infinite recursion

### `removeChild(self $node)`

[](#removechildself-node)

Remove given childnode

### `empty()`

[](#empty)

Remove all childnode

### `detach()`

[](#detach)

Remove childnode from its parent and returns it available to be attached (insert,append) elsewhere

### `cloneNode()`

[](#clonenode)

Returns an exact node clone, excluding its parent

### `getPrevSibling()`

[](#getprevsibling)

Returns previous sibling

### `getNextSibling()`

[](#getnextsibling)

Returns next sibling

### `querySelector(string $selector)`

[](#queryselectorstring-selector)

Non complex css selectors supported Supported selectors are: .class (ex: .intro) - Selects all elements with class="intro" .class1.class2 (ex: .name1.name2) - Selects all elements with both name1 and name2 set within its class attribute .class1 .class2 (ex: .name1 .name2) - Selects all elements with name2 that is a descendant of an element with name1 #id (ex: #firstname) - Selects the element with id="firstname" element (ex: p) - Selects all &lt;p&gt; elements element.class (ex: p.intro) - Selects all &lt;p&gt; elements with class="intro" element element (ex: div p) - Selects all &lt;p&gt; elements inside &lt;div&gt; elements element&gt;element (ex: div &gt; p) - Selects all &lt;p&gt; elements where the parent is a &lt;div&gt; element element+element (ex: div + p) - Selects the first &lt;p&gt; element that is placed immediately after &lt;div&gt; elements element1~element2 (ex: p ~ ul) - Selects every &lt;ul&gt; element that is preceded by a &lt;p&gt; element \[attribute\] (ex: \[target="value"\]) - Selects all elements with a target attribute having value 'value'

### `querySelectorAll(string $selector)`

[](#queryselectorallstring-selector)

Returns any node found which match the given selector Non complex css selectors supported

###  Health Score

29

—

LowBetter than 59% of packages

Maintenance29

Infrequent updates — may be unmaintained

Popularity13

Limited adoption so far

Community14

Small or concentrated contributor base

Maturity54

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 79.2% 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 ~32 days

Recently: every ~67 days

Total

10

Last Release

1007d ago

Major Versions

1.1 → 2.02023-08-15

### Community

Maintainers

![](https://www.gravatar.com/avatar/bab7f73e56ac36af8baecca411453051a4bf32ad09dadd470bf3f2386287634e?d=identicon)[florinbotea](/maintainers/florinbotea)

---

Top Contributors

[![florin-botea](https://avatars.githubusercontent.com/u/59554192?v=4)](https://github.com/florin-botea "florin-botea (331 commits)")[![florinbotea1693](https://avatars.githubusercontent.com/u/55512506?v=4)](https://github.com/florinbotea1693 "florinbotea1693 (75 commits)")[![php-templates](https://avatars.githubusercontent.com/u/116520363?v=4)](https://github.com/php-templates "php-templates (12 commits)")

---

Tags

dom-parserphpphp-template-enginetemplate-engineview-modularityvirtual-domphptemplates

### Embed Badge

![Health badge](/badges/php-templates-php-templates/health.svg)

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

###  Alternatives

[endroid/qr-code-bundle

Endroid QR Code Bundle

32110.6M17](/packages/endroid-qr-code-bundle)[gamajo/template-loader

A class for your WordPress plugin, to allow loading template parts with fallback through the child theme &gt; parent theme &gt; plugin

29647.0k5](/packages/gamajo-template-loader)[devanych/view-renderer

Simple PHP View Renderer

153.2k1](/packages/devanych-view-renderer)

PHPackages © 2026

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