☕ Latte: the intuitive and fast template engine for those who want the most secure PHP sites.

Overview

Latte: amazing template engine for PHP

Downloads this Month Tests Coverage Status Latest Stable Version License

Introduction

Latte is a template engine for PHP which eases your work and ensures the output is protected against vulnerabilities, such as XSS.

  • Latte is fast: it compiles templates to plain optimized PHP code.
  • Latte is secure: it is the first PHP engine introducing content-aware escaping.
  • Latte speaks your language: it has intuitive syntax and helps you to build better websites easily.

Documentation can be found on the website.

Support Latte

Do you like Latte? Are you looking forward to the new features?

Buy me a coffee

Thank you!

Getting Started

Although PHP is originally a templating language, it is not particularly suited for writing templates. Let's have a look at an example of a PHP template that prints an array $items as a list:

<?php if ($items): ?>
	<?php $counter = 1 ?>
	<ul>
	<?php foreach ($items as $item): ?>
		<li id="item-<?php echo $counter++ ?>"><?php
		echo htmlSpecialChars(mb_convert_case($item, MB_CASE_TITLE)) ?>
		</li>
	<?php endforeach ?>
	</ul>
<?php endif?>

The code is rather confusing. Moreover, we must not forget to call htmlSpecialChars function. That's why there are so many different template engines for PHP. One of the best template engines is part of Nette Framework and it is called Latte. You'll love it!

The same template as the one above can be written easily in Latte:

<ul n:if="$items">
{foreach $items as $item}
	<li id="item-{$iterator->counter}">{$item|capitalize}</li>
{/foreach}
</ul>

As you can see there are two types of macros:

  • macro in braces, for example {foreach …}
  • n:macro, for example n:if="…"

How to render template? Just install Latte (see below) and run this code:

$latte = new Latte\Engine;
$latte->setTempDirectory('/path/to/tempdir');
$parameters['items'] = array('one', 'two', 'three');
$latte->render('template.latte', $parameters);

Installation

The recommended way to install Latte is via Composer (alternatively you can download package):

composer require latte/latte

Latte requires PHP version 7.1 and supports PHP up to 8.0.

Usage

You can find detailed description of all the default macros on the extra page. Furthermore, you can make your own macros.

Each pair macro, such as {if} … {/if}, operating upon single HTML element can be written in n:macro notation. So, it is possible to write the {foreach} macro in the same manner:

<ul n:if="$items">
	<li n:foreach="$items as $item">{$item|capitalize}</li>
</ul>

With n:macros you can do much more interesting tricks as you will see in a moment.

{$item|capitalize} macro which prints the $item variable contains so called filter, in this case the capitalize filter which makes the first letter of each word uppercase.

Very important feature of Latte is that it escapes variables by default. Escaping is needed when printing a variable because we have to convert all the characters which have a special meaning in HTML to other sequences. In case we forget it can lead to a serious security hole called Cross Site Scripting (XSS).

Because of different escaping functions that are needed in different documents and different parts of a page, Latte features a unique technology of Context-Aware Escaping which recognizes the context in which the macro is placed and chooses the right escaping mode. You don't have to worry that your coder forgets about it causing you goose bumps because of a security hole. Which is great!

If the $item variable stores an HTML code and you want to print it without any alteration you just add the modifier noescape: {$item|noescape}. Forgetting the modifier mark won't cause any security holes in spirit of „less code, more security“ principle.

You can still use PHP inside the macros normally, including comments as well. But Latte also extends the PHP syntax with three pleasant features:

  1. array can be written as [1, 2, 3], which is the same as array(1, 2, 3) in PHP
  2. we can omit quotes around the strings consisting of letters, numbers and dashes
  3. short condition notation $a ? 'b' which is the same as $a ? 'b' : null in PHP

For example:

{foreach [a, b, c] as $id} ... {/foreach}

{$cond ? hello}  // prints 'hello' if $cond equals true

Latte also has a {* comment macro *} which doesn't get printed to the output.

n:macros

We showed that n:macros are supposed to be written directly into HTML tags as their special attributes. We also said that every pair macro (e.g. {if} … {/if}) can be written in n:macro notation. The macro then corresponds to the HTML element in which it is written:

{var $items = ['I', '♥', 'Nette Framework']}

<p n:foreach="$items as $item">{$item}</p>

Prints:

<p>I</p>
<p></p>
<p>Nette Framework</p>

By using inner- prefix we can alter the behavior so that the macro applies only to the body of the element:

<div n:inner-foreach="$items as $item">
	<p>{$item}</p>
	<hr>
</div>

Prints:

<div>
	<p>I</p>
	<hr>
	<p></p>
	<hr>
	<p>Nette Framework</p>
	<hr>
</div>

Or by using tag- prefix the macro is applied on the HTML tags only:

<p><a href="{$url}" n:tag-if="$url">Title</a></p>

Depending on the value of $url variable this will print:

// when $url is empty
<p>Title</p>

// when $url equals 'https://nette.org'
<p><a href="https://nette.org">Title</a></p>

However, n:macros are not only a shortcut for pair macros, there are some pure n:macros as well, for example the coder's best friend n:class macro.

Filters

Latte allows calling filters by using the pipe sign notation (preceding space is allowed):

<h1>{$heading|upper}</h1>

Filters (or modifiers) can be chained, in that case they apply in order from left to right:

<h1>{$heading|lower|capitalize}</h1>

Parameters are put after the filter name separated by colon or comma:

<h1>{$heading|truncate:20,''}</h1>

See the summary of standard filters and how to make user-defined filters.

In templates we can use functions which change or format the data to a form we want. They are called filters. See the summary of the default filters.

Filter can be registered by any callback or lambda function:

$latte = new Latte\Engine;
$latte->addFilter('shortify', function ($s) {
	return mb_substr($s, 0, 10); // shortens the text to 10 characters
});

In this case it would be better for the filter to get an extra parameter:

$latte->addFilter('shortify', function ($s, $len = 10) {
	return mb_substr($s, 0, $len);
});

We call it in a template like this:

<p><?php echo $template->shortify($text, 100); ?></p>

Latte simplifies the notation - filters are denoted by the pipe sign, they can be chained (they apply in order from left to right). Parameters are separated by colon or comma:

<p>{$text|shortify:100}</p>

Performance

Latte is fast. It compiles the templates to native PHP code and stores them in cache on the disk. So they are as fast as if they would have been written in pure PHP.

The template is automatically recompiled each time we change the source file. While developing you just need to edit the templates in Latte and changes are visible in your browser instantly.

Debugging

With each error or typo you will be informed by the Debugger with all the luxury. The template source code is displayed and the red line marks the error showing error message as well. With just a single click you can open the template in your favorite editor and fix the error at once. Easy peasy!

If you are using an IDE with code stepping you can go through the generated PHP code of the template.

Usability

Latte syntax wasn't invented by engineers but came up from webdesigner's practical requests. We were looking for the friendliest syntax with which you can write even the most problematic constructions comfortably enough. You will be surprised how much help Latte can be.

You can find macros for advanced layout managing, for template inheritance, nested blocks and so on. Syntax comes from PHP itself so you don't have to learn anything new and you can leverage your know-how.

Context-Aware Escaping

Although the Cross Site Scripting (XSS) is one of the trivial ways of exploiting a web page it is the most common vulnerability but very serious. It can lead to identity theft and so on. The best defense is consistent escaping of printed data, ie. converting the characters which have a special meaning in the given context.

If the coder omits the escaping a security hole is made. That's why template engines implement automated escaping. The problem is that the web page has different contexts and each has different rules for escaping printed data. A security hole then shows up if the wrong escaping functions are used.

But Latte is sophisticated. It features unique technology of Context-Aware Escaping which recognizes the context in which the macro is placed and chooses the right escaping mode. What does that mean?

Latte doesn't need any manual work. All is done automatically, consistently and correctly. You don't have to worry about security holes.

Lets see how it works:

<p onclick="alert({$movie})">{$movie}</p>

<script>var movie = {$movie};</script>

If $movie variable stores 'Amarcord & 8 1/2' string it generates the following output. Notice different escaping used in HTML and JavaScript and also in onclick attribute:

<p onclick="alert(&quot;Amarcord &amp; 8 1\/2&quot;)">Amarcord &amp; 8 1/2</p>

<script>var movie = "Amarcord & 8 1\/2";</script>

Thanks to Context-Aware Escaping the template is simple and your application perfectly secured against Cross Site Scripting. You can use PHP variables natively inside the JavaScript!

JavaScript

Strings in JavaScript are escaped including quotes. If you want to put variable into another string, simply concatenate them:

<script>
	alert('Hello ' + {$name} + '!');  # good
	alert('Hello {$name} !');  # bad
</script>

A pretty output

Sticklers will enjoy the look of the HTML output which Latte generates. All tags are indented as they are supposed to. The code looks like it has been processed with some kind of HTML code beautifier :-)

Issues
  • Engine: optimized loadCacheFile() performance

    Engine: optimized loadCacheFile() performance

    It's mostly similar to what DI\ContainerLoader does. Shouldn't we write the code to temporary file first and them use rename?


    Edit: I've tried slightly different approach. Will it work?

    opened by JanTvrdik 28
  • [WIP] snippets refactoring

    [WIP] snippets refactoring

    Snippets are now completely independent on the nette/application. I will send related PR to the nette/application in few minutes/hours.

    What do you think?

    opened by matej21 15
  • There is a way to bypass allowFunctions

    There is a way to bypass allowFunctions

    Version: 2.10.5

    Bug Description

    There is a way to bypass allowFunctions that will affect security.

    Steps To Reproduce

    <?php
    error_reporting(0);
    require 'vendor/autoload.php';
    $latte = new Latte\Engine;
    $policy = new Latte\Sandbox\SecurityPolicy;
    $policy->allowFilters($policy::ALL);
    $policy->allowMacros(['if','=']);
    $policy->allowFunctions(['strlen']);
    $latte->setPolicy($policy);
    $latte->setSandboxMode();
    $latte->setAutoRefresh(false);
    file_put_contents('index.latte',"{=system\x00('whoami')}");
    $latte->render('index.latte');
    

    This will execute the system function.

    Expected Behavior

    Should throw an error not allowed by system function

    Possible Solution

    Use rigorous regular expression segmentation, or add more rigorous judgments in isFunctionAllowed function

    opened by JinYiTong 14
  • Revert Filters: Update nl2br to return Latte\Runtime\Html object

    Revert Filters: Update nl2br to return Latte\Runtime\Html object

    Former change could cause potential hidden XSS errors as the whole string was being unescaped.

    This reverts commit 86b55f5d8e7b0ed182404df987107e905a7f974f.

    opened by finwe 13
  • Throwing an exception in acquireLock(...) fails

    Throwing an exception in acquireLock(...) fails

    Version: 2.10 PHP: 8.0.3

    Bug Description

    Throwing an exception at Engine.php:247 fails as Latte expects the function error_get_last() to always return an array from what it tries to read the message key. However, the aforementioned function can also return NULL, see https://www.php.net/manual/en/function.error-get-last.php

    throw new RuntimeException("Unable to create directory '$dir'. " . error_get_last()['message']);
    

    Steps To Reproduce

    set_error_handler('myErrorHandler');// <- this is what makes the error_get_last() func to always return NULL instead of an array
    $latte = new Latte\Engine();
    $latte->setTempDirectory('temp');// <- make sure your app can't access or make that dir!!!
    $output = $latte->renderToString('random_template.latte');
    
    opened by sukovf 13
  • Latte 2.3 and 2.2 not compatible with PHP 7.2

    Latte 2.3 and 2.2 not compatible with PHP 7.2

    Version: 2.3.* and 2.2.* (maybe older versions too, 2.4.* works fine)

    Bug Description

    composer.json allows PHP 7.2, but with this version of PHP, Object is not allowed as class name : Fatal error: Cannot use 'Object' as class name as it is reserved in /var/www/phpbenchmarks/benchmark/latte/vendor/latte/latte/src/Latte/Object.php on line 16

    Steps To Reproduce

    Hello World snippet to reproduce it :

    $latte = (new Latte\Engine)
        ->setTempDirectory($cacheDir)
        ->setAutoRefresh(true);
    
    $latte->render(__DIR__ . '/templates/hello-world.latte');
    

    Expected Behavior

    Don't allow PHP >= 7.2

    Possible Solution

    Change class name, but i think it could not be changed without BC ?

    opened by phpbenchmarks 13
  • Rewriting Git history has real-world consequences

    Rewriting Git history has real-world consequences

    There are at least two different commits representing Latte v2.3.5:

    • 3d47b0af6967c99df203e98cce6201b5d84b5ea4
    • 36d5f660b08f2153c2c0a99eb5f29c3b4f268698

    I really don't know why that's the case. If the original 2.3.5 release contained a bug, what really should have been done was to release a new version 2.3.6 with the bugfix.

    Because of this selfish change, our team cannot continue working on our application this morning. composer install failed during our cronjobs tonight which resulted in corrupted application on our dev server.

    I propose to never forcepush to master and to never rewrite published tags.

    opened by ondrejmirtes 11
  • Including parent block works only once

    Including parent block works only once

    Lets have theese two templates:

    @layout.latte

    {block scripts}
      ...some code
    {/block}
    

    page.latte

    {layout @layout.latte}
    {block scripts}
      {include parent}
      {include parent}
    {/block}
    

    It ends up with error "Cannot include undefined parent block 'scripts'".

    If I delete one include, it will work fine.

    opened by EdaCZ 11
  • PHP 8.1: strftime depreceted

    PHP 8.1: strftime depreceted

    Version: 2.10.6

    Bug Description

    strftime is deprecated in PHP 8.1 and filter date could produce error. https://github.com/nette/latte/blob/c0cfd1b1a56ed512de9358183d8c344cbb75a4dc/src/Latte/Runtime/Filters.php#L439

    Steps To Reproduce

    {var $str = '2021-12-01 00:00:00'}
    ({$str|date:'%Y-%m-%d'})
    

    Expected Behavior

    not throwing anything

    Possible Solution

    add @ or replace it all together? :)

    opened by pkristian 2
  • Check if template implements given interface

    Check if template implements given interface

    Hello,

    Quite often I need to get a template from a user that can render my mandatory parameters and not use anything else. For example, an email template in an e-shop can only use predefined parameters, and anything extra will be rendered incorrectly (because the variable does not exist).

    Latte could include a native way to see what all parameters the template implements (plus a list of keys in the array, if it's a $var['abcd'] notation for example). At the same time, there should be a check.

    The implementation may use, for example, a native PHP interface where we scan for real typehints for methods, or at least an array of parameters from the user.

    I know I can compile the Latte template to native PHP code, and then verify the connection with PhpStan, but this behavior is simply not possible to run on a production server where we receive a specific template from the user.

    Thank you.

    opened by janbarasek 2
  • Propagate variable types to generated code to allow statical analysis

    Propagate variable types to generated code to allow statical analysis

    • new feature
    • BC break? no

    With this change Latte will propagate known types infomation from {varType}, {define} and {parameters} into compiled PHP code in form of /** @var type $var */ annotations. This will allow statical anylysis of resulting code by static analysers like PHPStan, Psalm, etc.

    See discussion about this feature here https://github.com/nette/latte/issues/262

    (Previous PR targeted onto master here #275)

    opened by MartinMystikJonas 2
  • Incorrect behavior of n:iterateWhile (differs from

    Incorrect behavior of n:iterateWhile (differs from "non n-tag" version)

    Version: 2.10.3

    Bug Description

    When using n-tag version of iterateWhile, generated output does not equal to non-tagged version (first item is skipped?).

    Steps To Reproduce

    https://fiddle.nette.org/latte/#a8012a3587 (broken n-tag version) vs https://fiddle.nette.org/latte/#f9a61fe9b9 (working non-tagged version)

    Expected Behavior

    Generated result is same for both iterateWhile and n:iterateWhile versions

    Possible Solution

    By comparing generated templates, it looks like the condition is written to beginning of the foreach cycle when using n-tag version...

    opened by khorsky 0
  • \DatePeriod in foreach does not work with {sep} in PHP 8

    \DatePeriod in foreach does not work with {sep} in PHP 8

    Version: latte 2.10.3, PHP 8.0.6

    Bug Description

    When iterating \DatePeriod object in latte, it works fine, but when using {sep} it skips to every other DateTime object. So the result is for example 2021-01-01, 2021-01-03, ...

    It is only in case of PHP 8.0, PHP 7.4 works as expected.

    Steps To Reproduce

       public function renderDefault() {
            $start = \DateTime::createFromFormat("Y-m-d", "2021-01-01");
            $end = \DateTime::createFromFormat("Y-m-d", "2021-01-30");
            $this->template->period = new \DatePeriod($start, \DateInterval::createFromDateString('1 day'), $end)
       }
    
    {foreach $period as $day}
        {$day|date:'Y-m-d'}{sep}<br/>{/sep}
    {/foreach}
    

    Results in

    2021-01-01
    2021-01-03
    2021-01-05
    ...
    

    Possible Solution

    It is caused by \Latte\Runtime\CachingIterator::isLast() call, and when calling \Latte\Runtime\CachingIterator::hasNext() it is broken as well. But when using PHP's \CachingIterator::hasNext() it looks like everything is fine. But I have no idea how to fix this.

    opened by janfejtek 0
  • Notice: Undefined property: stdClass::$ifcontent

    Notice: Undefined property: stdClass::$ifcontent

    Version: v2.4.9

    Notice: Undefined property: stdClass::$ifcontent in /var/www...
    

    Latte code

    <div n:ifcontent n:if="false"></div>
    

    Generated code

    <?php
    		ob_start(function () {});
    		if (false) {
    			?>	<div><?php
    			ob_start();
    			$this->global->ifcontent = ob_get_flush();
    ?></div>
    <?php
    		}
    		if (rtrim($this->global->ifcontent) === "") ob_end_clean();
    		else echo ob_get_clean();
    ?>
    

    Screenshot 2021-07-07 at 10 46 38

    https://fiddle.nette.org/latte/#58bb87ac17

    opened by michalhlavka 0
  • {skipIf} does not avoid printing last {sep}

    {skipIf} does not avoid printing last {sep}

    Version: 2.10.3

    Steps To Reproduce

    {foreach [1, 2, 3] as $item}
        {skipIf $item === 3}
        {$item}{sep}, {/sep}
    {/foreach}
    

    https://fiddle.nette.org/latte/#14e8be81e2

    Expected Behavior

    The last comma should not be printed.

    opened by JanTvrdik 2
  • Propagate type information in compiled template code to allow static analysis

    Propagate type information in compiled template code to allow static analysis

    I just finished first draft of script that uses PHPStan to satic analysis of compiled Latte templates in our projects.

    One think I noticed is that {varType} or {templateType} macros does not propagate any type related information to compiled Latte templates so PHPStan cannot check it.

    Is there any plan to address this?

    I could try to prepare PR which will address this but I would like to disccuss what approach to take here.

    One option would be to simply add relevant /** @var type $variable */ annotations after each extract of parameters.

    So insted of:

    extract($this->params);
    $a->call(); // PHPStan: OK
    

    it would be:

    extract($this->params);
    /** @var string $a */
    $a->call(); // PHPStan error: Cannot call method call() on string.
    

    Another IMHO better approach would be to generate known params as template properties and instead of addressign them as $variable use $this->variable if variable is known but I am not sure how difficult that change would be.

    And for {templateType} another option woudl be to add property $template of given type, populate it with passed values and address variables from templateType as $this->template->variable.

    opened by MartinMystikJonas 13
  • Short named arguments syntax fails with key wrapped in apostrophes or quotation marks

    Short named arguments syntax fails with key wrapped in apostrophes or quotation marks

    Version: 2.10.2

    Bug Description

    Apostrophes and quotation marks are not accepted by keys in [key: value] syntax

    With => were all of these possible:

    • {link paginate!, page => 1}
    • {link paginate!, 'page' => 1}
    • {link paginate!, "page" => 1}

    With ::

    • {link paginate!, page: 1} works properly
    • {link paginate!, 'page': 1} generates $this->global->uiControl->link("paginate!", ['page': 1]) which results into \ParseError

    Expected Behavior

    Throw exception that apostrophes and quotation marks are not supported anymore or generate correct code.

    opened by mabar 2
  • Cannot redeclare block when using condition in {embed}

    Cannot redeclare block when using condition in {embed}

    Version: 2.9.2, 2.10.0

    Bug Description

    Parser throws: Latte\CompileException: Cannot redeclare block 'someBlock' in ...

    Steps To Reproduce

    Run Latte with this code in a template file:

    {define aaa}
     <span>{block someBlock}{/block}</span>
    {/define}
    
    {embed aaa}
    	{if 3 === 4}
    		{block someBlock}a{/block}
    	{else}
    		{block someBlock}b{/block}
    	{/if}
    {/embed}
    
    

    Expected Behavior

    Output <span>b</span>

    Note that I can't wrap {if} with {block} as I define multiple blocks so it would lead to repeating conditional logic in every block.

    opened by dakur 3
Releases(v2.10.8)
  • v2.10.8(Jan 4, 2022)

  • v2.9.6(Jan 4, 2022)

  • v2.8.8(Jan 4, 2022)

  • v2.10.7(Dec 21, 2021)

    • BlueScreenPanel: added source mapping & files creating in Tracy 2.9
    • Filters: better error message for deprecated strftime()
    • improved coding standard
    Source code(tar.gz)
    Source code(zip)
  • v2.10.6(Nov 26, 2021)

    This is a security release.

    • Parser: removes all control characters from template [Closes #279]
    • PhpWriter::removeCommentsPass() replaces comment with space to prevent unwanted result
    • isNext() a isPrev() called with SIGNIFICANT
    • linter: warn on BOM and deprecated stuff
    • linter: Add shebang so it can be run directly (#277)
    Source code(tar.gz)
    Source code(zip)
  • v2.9.5(Nov 26, 2021)

    This is a security release.

    • Parser: removes all control characters from template [Closes #279]
    • PhpWriter::removeCommentsPass() replaces comment with space to prevent unwanted result
    • isNext() a isPrev() called with SIGNIFICANT
    Source code(tar.gz)
    Source code(zip)
  • v2.8.7(Nov 26, 2021)

    This is a security release.

    • Parser: removes all control characters from template [Closes #279]
    • PhpWriter::removeCommentsPass() replaces comment with space to prevent unwanted result
    • isNext() a isPrev() called with SIGNIFICANT
    Source code(tar.gz)
    Source code(zip)
  • v2.10.5(Oct 27, 2021)

    • added Latte linter
    • Filters: compatibility with JS binding II.
    • {ifset block, block} fixed
    • // comment and # comment are forbidden inside tags
    • Blueprint: used syntax highlighter
    • Template::getParameters() skips $_l $_g
    Source code(tar.gz)
    Source code(zip)
  • v2.9.4(Oct 27, 2021)

    This is a security release.

    • Blueprint: fixed compatibility with PhpGenerator 3.6.2
    • Filters: compatibility with JS binding II.
    • // comment and # comment are forbidden inside tags
    Source code(tar.gz)
    Source code(zip)
  • v2.8.6(Oct 27, 2021)

    This is a security release.

    • Blueprint: fixed compatibility with PhpGenerator 3.6.2
    • Filters: compatibility with JS binding II.
    • // comment and # comment are forbidden inside tags
    • {capture} creates Html object only in HTML-TEXT context
    • {_translate} & {capture} passes full content-type to FilterInfo
    • {block|filter} passes full content-type to FilterInfo
    Source code(tar.gz)
    Source code(zip)
  • v2.7.4(Oct 27, 2021)

    • Blueprint: fixed compatibility with PhpGenerator 3.6.2
    • Filters: compatibility with JS binding II.
    • // comment and # comment are forbidden inside tags

    Branch 2.7 is no longer supported

    Source code(tar.gz)
    Source code(zip)
  • v2.6.4(Oct 27, 2021)

  • v2.5.7(Oct 27, 2021)

  • v2.10.4(Oct 2, 2021)

    • support for PHP 8.1
    • Blueprint: skips $_l $_g
    • BlockMacros: removed unnecesary $ʟ_nm (after f88777b0799)
    • BlockMacros: filters are not allowed in {include parent}
    • BlockMacros: fixed {include this} in {block}
    • LattePanel: removed dependency on Nette #274
    • PhpWriter::quotingPass supports 'default =>' syntax #267
    • Filters: flipepd string/array tests
    • CoreMacros: Arguments are not allowed in n:ifcontent
    Source code(tar.gz)
    Source code(zip)
  • v2.9.3(Feb 24, 2021)

    • {capture} creates Html object only in HTML-TEXT context
    • {_translate} & {capture} passes full content-type to FilterInfo
    • {block|filter} passes full content-type to FilterInfo
    • Policy::createSafePolicy() added new function
    • Filters: escapes JS binding {{ }}
    • allows {else} in {first}, {last}, {sep} #247
    • BlockMacros: removed empty line after {define} #251
    • {embed}: reimplemented, creates new block layers dynamically, uses stack
    Source code(tar.gz)
    Source code(zip)
  • v2.7.3(Feb 24, 2021)

    • {capture} creates Html object only in HTML-TEXT context
    • {_translate} & {capture} passes full content-type to FilterInfo
    • {block|filter} passes full content-type to FilterInfo
    • Filters: escapes JS binding {{ }}
    Source code(tar.gz)
    Source code(zip)
  • v2.6.3(Feb 24, 2021)

    • {capture} creates Html object only in HTML-TEXT context
    • {_translate} & {capture} passes full content-type to FilterInfo
    • {block|filter} passes full content-type to FilterInfo
    • Filters: escapes JS binding {{ }}
    Source code(tar.gz)
    Source code(zip)
  • v2.5.6(Feb 24, 2021)

    • {capture} creates Html object only in HTML-TEXT context
    • {_translate} & {capture} passes full content-type to FilterInfo
    • {block|filter} passes full content-type to FilterInfo
    • Filters: escapes JS binding {{ }}
    Source code(tar.gz)
    Source code(zip)
  • v2.10.2(Feb 24, 2021)

    • utilization of function inlining
    • |replace improved, accepts associative array as $search
    • |sort accepts callback
    • |sort maintains index association
    • added filters & functions: even(), odd(), divisibleBy(), first(), last(), |join, |slice, |round, |floor, |ceil, |explode, |split, |random, |spaceless
    • filter |query accepts with string
    • Filters: escapes JS binding {{ }}
    • improved detection of unexpected assignments {include $var = ...} [Closes #258]
    • added more comments /* line */
    Source code(tar.gz)
    Source code(zip)
  • v2.10.3(Feb 22, 2021)

    • {embed}: outer variables are promoted inside {block}
    • {embed}: reimplemented, creates new block layers dynamically, uses stack
    • Policy::createSafePolicy() added new filters and tags
    • Filters: |sort accepts only Closure for security reasons
    • Template::render() restores output buffer #260
    • LattePanel: added option to disable parameters dumping #259
    • {capture} creates Html object only in HTML-TEXT context (BC break)
    • {_translate} & {capture} passes full content-type to FilterInfo (BC break)
    • {block|filter} passes full content-type to FilterInfo (BC break)
    Source code(tar.gz)
    Source code(zip)
  • v2.10.1(Jan 26, 2021)

    • added {iterateWhile}
    • added {trace}
    • added Tracy bridge
    • added filter |query
    • added PHP attributes Latte\Attributes\TemplateFunction & TemplateFilter
    • added n:tag [Closes #248]
    • implemented {embed block}
    • added short array syntax [key: value]
    • Engine: added addFilterLoader(), replacement for addFilter(null)
    • warnings converted to exceptions (BC break)
    • added phpDoc comments to block methods
    • PhpWriter: added placeholder %node.line
    • BlueScreenPanel: add check for nullable $e->sourceName (#254)
    Source code(tar.gz)
    Source code(zip)
  • v2.9.2(Dec 16, 2020)

    • added {parameters}
    • detects unexpected assignments {include $var = ...}
    • PhpWriter::quotingPass() supports named arguments without parentheses
    • internal variables are prefixed $ʟ_
    • Fixes variables promotion after ce2b11861 comments in #178
    • Defaults: better info when mbstring extension or nette/utils are missing #244
    • SnippetDriver: dynamic snippets runtime check

    For the details you can have a look at the diff.

    Source code(tar.gz)
    Source code(zip)
  • v2.8.4(Dec 16, 2020)

    • internal variables are prefixed $ʟ_
    • Compiler: improved code indentation
    • BlockMacros: "extends check" skipped for nested blocks #227
    • Template::render() removed dead code after 5972e7206
    • PhpHelpers::reformatCode() appends correctly semicolon after '${""}'
    • CoreMacros: fixed regexp

    For the details you can have a look at the diff.

    Source code(tar.gz)
    Source code(zip)
  • v2.5.5(Dec 1, 2020)

  • v2.4.9(Dec 1, 2020)

  • v2.9.1(Nov 24, 2020)

    • Compiler: improved code indentation
    • BlockMacros: added {include file with blocks} as a successor to {includeblock} (#152)
    • BlockMacros: combination of n:snippet & n:ifcontent is forbidden #243
    • Revert "{snippetArea} requires parameter" #240
    • BlockMacros: parameters in {define} can have default values
    • BlockMacros: {define} accepts named parameters #184 #198
    • BlockMacros: fixed variables visibility between blocks depend on block order, alternative solution #178"
    • BlockMacros: supports expression as block/snippet name
    • CoreMacros: supports expression in include/extends
    • {embed} can contain {import}
    • Only top-level {block} is auto-closed
    • SecurityPolicy: added new tags & filters
    • changed \RuntimeException to Latte\RuntimeException
    • changed word 'modifier' --> 'filter' in exception messages
    • Revert "Template imported via {import} can use {extends}"
    • CoreMacros: {breakIf} and {continueIf} checks ancestors instead of parents #239
    • Defaults: filter 'webalize' is optional and depends on nette/utils #238
    • CoreMacros: modified use of temporary variables
    • CoreMacros: fixed {var} in {switch} usage #237
    • Compiler: tag name can contain dots, dashes and colons #236
    • BlockMacros: removed checks if dynamic snippet is used in {snippet} or {snippetArea} #134

    For the details you can have a look at the diff.

    Source code(tar.gz)
    Source code(zip)
  • v2.9.0(Nov 16, 2020)

    New Features

    • possibility to {include block from file}
    • filter |sort, |clamp & custom function clamp()
    • added {ifchanged}
    • added {skipIf}
    • added {foreach} {else} {/foreach}
    • added {try} & {else} & {rollback}
    • added {embed file.latte}
    • added local blocks {block local name} & {define local name}
    • {case 1, 2, 3} accepts more than one option
    • syntax {include block foo} and {include file foo}
    • syntax {ifset block foo}
    • syntax {ifset #$blockName}
    • added $iterator->parent, returns the iterator surrounding the current one
    • added $iterator->counter0, returns 0-indexed counter
    • implemented support for named arguments
    • added null-coalescing-safe operator ??->

    Improvements & Fixes

    • template code: direct HTML changed to 'echo' statements
    • BlockMacros: fixed variables visibility between blocks depend on block order [Closes #178]
    • FilterExecutor::filterContent() converts HtmlStringable to text [Closes #215]
    • Compiler: supports uppercases AND|OR|XOR [Closes #172]
    • BlockMacros: big refactoring
    • Template & BlockMacros: used new class Block, removed $blockQueue & $blockTypes
    • Template: removed old accumulator $_b (deprecated in 2.4, BC break)
    • added Defaults: default filters list moved here from FilterExecutor
    • CoreMacros: replaced global queuened temporary variables with local ones
    • BlockMacros: snippet driver wrapped in try ... finally
    • Parser: fixed parsing {__()} [Closes #226]
    • checks for valid macro/filter/function/block names
    • macros validates arguments, modifiers, position (MacroNode::validate())
    • {debugbreak} uses only xdebug
    • changed word 'macro' --> 'tag' in exception messages
    • CachingIterator: do not ask when not in valid state (#230)
    • improved typehints
    • PhpHelpers::reformatCode() appends correctly semicolon after '${""}'

    Changes

    • Colons as argument separators in modifiers are deprecated (BC break)
    • optional chaining: operator ?-> in Latte behaves the same as in PHP (BC break)
    • optional chaining: deprecated support for $var? and $obj?::$prop to be consistent with PHP 8 (BC break)
    • internal variables are prefixed $__ and disallowed to be used
    • Template: changed $contentType and $blocks to constants CONTENT_TYPE & BLOCKS
    • Template & BlockMacros: moved snippets to own layer, removed '_' prefix
    Source code(tar.gz)
    Source code(zip)
  • v2.8.3(Nov 4, 2020)

    • compatible with PHP 8.0
    • CoreMacros: varType accepts complex types #234
    • removed short ternary deprecation notice
    • added Template::getBlockNames()
    • coding style

    For the details you can have a look at the diff.

    Source code(tar.gz)
    Source code(zip)
  • v2.7.2(Sep 29, 2020)

    • Filters::escapeJS: fixed escaping of CDATA #231
    • renamed HtmlString -> HtmlStringable
    • Parser::getLine() optimized & improved

    For the details you can have a look at the diff.

    Source code(tar.gz)
    Source code(zip)
  • v2.8.2(Sep 29, 2020)

    • Engine: added invokeFunction()
    • Filters::escapeJS: escapes slashes only when needed
    • Filters::escapeJS: fixed escaping of CDATA #231
    • PhpWriter: improved exception when |noescape or |nocheck is not expected

    For the details you can have a look at the diff.

    Source code(tar.gz)
    Source code(zip)
PHP Template Attribute Language — template engine for XSS-proof well-formed XHTML and HTML5 pages

PHPTAL - Template Attribute Language for PHP Requirements If you want to use the builtin internationalisation system (I18N), the php-gettext extension

PHPTAL 165 Dec 17, 2021
⚡️ Simple and fastly template engine for PHP

EasyTpl ⚡️ Simple and fastly template engine for PHP Features It's simple, lightweight and fastly. No learning costs, syntax like PHP template It is s

PHPPkg 14 Jan 3, 2022
PHP template engine for native PHP templates

FOIL PHP template engine, for PHP templates. Foil brings all the flexibility and power of modern template engines to native PHP templates. Write simpl

Foil PHP 163 Nov 20, 2021
Smarty is a template engine for PHP, facilitating the separation of presentation (HTML/CSS) from application logic.

Smarty 3 template engine smarty.net Documentation For documentation see www.smarty.net/docs/en/ Requirements Smarty can be run with PHP 5.2 to PHP 7.4

Smarty PHP Template Engine 1.9k Jan 11, 2022
View template engine of PHP extracted from Laravel

Blade 【简体中文】 This is a view templating engine which is extracted from Laravel. It's independent without relying on Laravel's Container or any others.

刘小乐 145 Aug 13, 2021
Twig Template Engine to Phalcon PHP

Twig Template Engine to Phalcon PHP

Vinicius 3 Jun 17, 2021
Standalone Skeltch templating engine for PHP

SkeltchGo is a standalone version of Glowie Skeltch templating engine for PHP, intented to use from outside the framework.

glowie 1 Nov 5, 2021
SwitchBlade: Custom Directives for the Laravel Blade templating engine

SwitchBlade: Custom Directives for the Laravel Blade templating engine

Awkward Ideas 9 Sep 2, 2021
A complete and fully-functional implementation of the Jade template language for PHP

Tale Jade for PHP Finally a fully-functional, complete and clean port of the Jade language to PHP — Abraham Lincoln The Tale Jade Template Engine brin

Talesoft 93 May 4, 2021
The free-to-use template for your Imagehost-website made with PHP, HTML and CSS!

The free-to-use template for your Imagehost-website made with PHP, HTML and CSS! Some information before we start This repo is only code related, to a

Ilian 4 Dec 15, 2021
The free-to-use template for your Imagehost-website made with PHP, HTML and CSS!

The free-to-use template for your Imagehost-website made with PHP, HTML and CSS! Some information before we start This repo is only code related, to a

Ilian 4 Dec 15, 2021
A SilverStripe Module with template methods to quickly make use of FocusPoint, LazySizes, and Object-fit

LazyFocusFit A SilverStripe module with template methods to quickly make use of FocusPoint, LazySizes and object-fit. Requirements PHP FocusPoint JS/C

Evans Hunt 8 Oct 12, 2021
Native PHP template system

Plates Plates is a native PHP template system that's fast, easy to use and easy to extend. It's inspired by the excellent Twig template engine and str

The League of Extraordinary Packages 1.3k Jan 7, 2022
A ready-to-use Model View Controller template in PHP

PHP-MVC-Template A ready-to-use Model View Controller template in PHP Use this repo as a template! (Or clone it) Start to configure your MVC file Afte

Loule | Louis 7 Dec 28, 2021
Provides a GitHub repository template for a PHP package, using GitHub actions.

php-package-template Installation ?? This is a great place for showing how to install the package, see below: Run $ composer require ergebnis/php-pack

null 262 Jan 16, 2022
A lightweight template parser used by PyroCMS.

Lex Lex is a lightweight template parser. Lex is released under the MIT License and is Copyrighted 2011 - 2014 PyroCMS Team. Change Log 2.3.2 Convert

PyroCMS 102 Nov 19, 2021
Laravel package template

REPLACE Simple and flexible package template. Usage Replace all occurances of REPLACE (case sensitive) with the name of the package namespace. E.g. th

ARCHTECH 48 Dec 4, 2021
The Templating component provides all the tools needed to build any kind of template system.

Templating Component The Templating component provides all the tools needed to build any kind of template system. It provides an infrastructure to loa

Symfony 984 Jan 10, 2022
Document templates Laravel package is intended for creating/managing user editable document template

Document Templates Introduction Document templates Laravel package is intended for creating/managing user editable document templates, with ability to

42coders 111 Dec 23, 2021