Marketplace

latte-templates

Invoke BEFORE creating or modifying .latte files. Provides Latte syntax, tags, filters, layouts, and extensions.

$ Installer

git clone https://github.com/nette/claude-code /tmp/claude-code && cp -r /tmp/claude-code/plugins/nette/skills/latte-templates ~/.claude/skills/claude-code

// tip: Run this command in your terminal to install the skill


name: latte-templates description: Invoke BEFORE creating or modifying .latte files. Provides Latte syntax, tags, filters, layouts, and extensions.

Latte Templating System

Latte is a secure templating engine with context-aware escaping, intuitive syntax, and powerful template inheritance.

composer require latte/latte

Basic Syntax

{* this is a comment *}
<ul n:if="$items">                {* n:attribute *}
{foreach $items as $item}         {* tag *}
	<li>{$item|capitalize}</li>   {* variable with filter *}
{/foreach}
</ul>

Printing Variables

{$name}                    {* prints escaped variable *}
{$user->name}              {* object property *}
{$items[0]}                {* array access *}
{='hello'|upper}           {* expression with filter *}
{$html|noescape}           {* disable escaping (use carefully!) *}

Filters

Filters modify output, written after |:

{$title|upper}                    {* HELLO *}
{$text|truncate:100}              {* shortens to 100 chars *}
{$price|number:2}                 {* formats number *}
{$date|date:'j. n. Y'}            {* formats date *}
{$name|lower|capitalize}          {* chained filters *}

Common filters: upper, lower, capitalize, truncate, number, date, noescape, escapeUrl, stripHtml, trim, replace, first, last, length, sort, reverse

For complete filter reference, see filters.md.

n:attributes

Pair tags can be written as HTML attributes:

{* These are equivalent: *}
{if $condition}<div>...</div>{/if}
<div n:if="$condition">...</div>

{* Applies to element content only: *}
<div n:inner-foreach="$items as $item">...</div>

{* Applies to tag only (not content): *}
<a href={$url} n:tag-if="$url">Link</a>

Conditions

{if $stock > 0}
	In stock
{elseif $onWay}
	On the way
{else}
	Not available
{/if}

{ifset $user}...{/ifset}          {* if variable exists *}

{* switch/case *}
{switch $type}
	{case admin}Administrator
	{case user}User
	{default}Guest
{/switch}

Loops

{foreach $items as $item}
	{$item->name}
{/foreach}

{foreach $items as $key => $item}
	{$key}: {$item}
{/foreach}

{* With else for empty arrays *}
{foreach $items as $item}
	<li>{$item}</li>
{else}
	<li>No items found</li>
{/foreach}

{* Iterator variable *}
{foreach $items as $item}
	{$iterator->counter}. {$item}  {* 1, 2, 3... *}
	{if $iterator->first}First!{/if}
	{if $iterator->last}Last!{/if}
{/foreach}

{* Helper tags *}
{foreach $items as $item}
	{first}<ul>{/first}
	<li>{$item}</li>
	{last}</ul>{/last}
	{sep}, {/sep}                  {* separator between items *}
{/foreach}

Variables

{var $name = 'John'}
{var $items = [1, 2, 3]}
{default $lang = 'en'}            {* only if not set *}

{capture $content}
	<p>Captured HTML</p>
{/capture}
{$content}

Template Inheritance

Layout template (@layout.latte):

<!DOCTYPE html>
<html>
<head>
	<title>{block title}Default{/block}</title>
</head>
<body>
	{block content}{/block}
</body>
</html>

Child template:

{layout '@layout.latte'}

{block title}My Page{/block}

{block content}
	<h1>Welcome</h1>
	<p>Content here</p>
{/block}

Including Templates

{include 'header.latte'}
{include 'item.latte', item: $item, showPrice: true}
{include $dynamicTemplate}

Blocks

{block sidebar}
	<aside>Sidebar content</aside>
{/block}

{include sidebar}                          {* print block *}
{include sidebar from 'other.latte'}       {* from another file *}

{* Reusable definitions with parameters *}
{define button, $text, $type = 'primary'}
	<button class="btn btn-{$type}">{$text}</button>
{/define}

{include button, 'Submit'}
{include button, 'Cancel', 'secondary'}

Common Tags Reference

TagDescription
{$var}Print escaped variable
{if}...{/if}Condition
{foreach}...{/foreach}Loop
{var $x = ...}Create variable
{include 'file'}Include template
{block name}...{/block}Define block
{layout 'file'}Extend layout
{do expression}Execute without output
{php code}Raw PHP (needs extension)
{dump $var}Debug dump (Tracy)

For complete tag reference, see tags.md.

Smart HTML Attributes

{* null removes attribute *}
<div title={$title}>

{* boolean controls presence *}
<input type="checkbox" checked={$isChecked}>

{* arrays in class *}
<div class={['btn', active => $isActive]}>

{* arrays JSON-encoded in data- *}
<div data-config={[theme: dark, count: 5]}>

n:class Helper

{foreach $items as $item}
	<a n:class="$item->active ? active, $iterator->first ? first, item">
		{$item->name}
	</a>
{/foreach}

Latte in Nette Applications

Template Organization Strategy

Keep templates with presenters:

Product/
├── ProductPresenter.php
├── default.latte
├── edit.latte
└── detail.latte

Layout placement follows presenter organization:

Admin/
├── @layout.latte           ← Admin-wide layout
├── Auth/
│   ├── @layout.latte       ← Auth-specific layout
│   └── AuthPresenter.php
└── Catalog/
	└── Product/
		├── ProductPresenter.php
		└── edit.latte

Template Partial Patterns

Shared template parts use @ prefix:

  • @layout.latte - layout templates
  • @form.latte - reusable form structures
  • @item.latte - list item templates

Template Class Strategy

Create template classes for complex presenters:

/**
 * @property-read ProductTemplate $template
 */
class ProductPresenter extends BasePresenter
{
}

class ProductTemplate extends Nette\Bridges\ApplicationLatte\Template
{
	public ProductRow $product;
	public array $variants;
	public ?CategoryRow $category;
}

When to use template classes:

  • Presenters with 5+ template variables
  • Complex data structures passed to templates
  • When you want full IDE support in templates

Template Type Declaration:

{templateType App\Presentation\Product\ProductTemplate}

<h1>{$product->name}</h1>
{foreach $variants as $variant}
	<div class="variant">{$variant->name} - {$variant->price}</div>
{/foreach}

Nette-specific Tags

{* Links *}
<a n:href="Product:detail $id">Detail</a>
<a href={link Product:detail $id}>Detail</a>
<a href={plink //Product:detail $id}>Absolute</a>

{* Components *}
{control productForm}
{control dataGrid}

{* AJAX Snippets *}
{snippet items}
	{foreach $items as $item}
		<div>{$item->name}</div>
	{/foreach}
{/snippet}

{* Forms *}
{form loginForm}
	{label username}{input username}
	{label password}{input password}
	{input submit}
{/form}

{* Assets (Nette Assets) *}
{asset 'admin.js'}
{asset 'front.css'}

Extension and Customization

Create single extension for entire application:

final class LatteExtension extends Latte\Extension
{
	public function getFilters(): array
	{
		return [
			'money' => fn($amount) => number_format($amount, 0, ',', ' ') . ' Kč',
		];
	}

	public function getFunctions(): array
	{
		return [
			'canEdit' => fn($entity) => $this->user->isAllowed($entity, 'edit'),
		];
	}
}

Register in config:

latte:
	extensions:
		- App\Presentation\Accessory\LatteExtension

Latte Configuration

latte:
	strictParsing: yes
	locale: cs

Anti-Patterns to Avoid

  • Don't put business logic in templates - templates display data, don't process it
  • Don't create deep template hierarchies - prefer composition over inheritance
  • Don't duplicate template code - extract to partials or components

Online Documentation

For detailed information beyond this reference, fetch from latte.nette.org:

When you need more details about a specific Latte feature not covered in this skill, use WebFetch to retrieve information from these URLs.