{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "Cecil - Templates",
  "home_page_url": "https://cecil.app/documentation/templates/",
  "feed_url": "https://cecil.app/documentation/templates/feed.json",
  "description": "Work with Twig layouts, templates and components.",
  "icon": "https://cecil.app/favicon.7ff4b89eec6dad139a7d2d6561543285.png",
  "favicon": "https://cecil.app/thumbnails/64x/favicon.7ff4b89eec6dad139a7d2d6561543285.png",
  "language": "en",
  "items": [
    {
      "id": "https://cecil.app/documentation/templates/lookup-rules/",
      "url": "https://cecil.app/documentation/templates/lookup-rules/",
      "title": "Organization and lookup rules",
      "summary": "Kinds of templates, naming convention, built-in templates and how a template is chosen for a page.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Organization and lookup rules\nFiles organization\nKinds of templates\nThere are three kinds of templates: layouts, components, and other templates. Layouts are used to render pages, and each layout can include templates and components.\nNaming convention\nTemplate files are stored in the layouts\/ directory and must be named according to the following convention:\nlayouts\/(&lt;section&gt;\/)&lt;type&gt;|&lt;layout&gt;.&lt;format&gt;(.&lt;language&gt;).twig\n\n&lt;section&gt; (optional)\nThe section of the page (e.g.: blog).\n&lt;type&gt;\nThe page type: home (or index) for homepage, list for list, page for page, etc. (See Lookup rules for details).\n&lt;layout&gt; (optional)\nThe custom layout name defined in the front matter of the page (e.g.: layout: my-layout).\n&lt;format&gt;\nThe output format of the rendered page (e.g.: html, rss, json, xml, etc.).\n&lt;language&gt; (optional)\nThe language of the page (e.g.: fr).\n\nExamples:\nlayouts\/home.html.twig       # `type` is \"homepage\"\nlayouts\/page.html.twig       # `type` is \"page\"\nlayouts\/page.html.fr.twig    # `type` is \"page\" and `language` is \"fr\"\nlayouts\/my-layout.html.twig  # `layout` is \"my-layout\"\nlayouts\/blog\/list.html.twig  # `section` is \"blog\"\nlayouts\/blog\/list.rss.twig   # `section` is \"blog\" and `format` is \"rss\"\n&lt;my-site&gt;\n├─ ...\n├─ layouts\n|  ├─ index.html.twig      # Used by type \"homepage\"\n|  ├─ list.html.twig       # Used by types \"homepage\" and \"section\"\n|  ├─ list.rss.twig        # Used by types \"homepage\" and \"section\", for RSS output format\n|  ├─ page.html.twig       # Used by type \"page\"\n|  ├─ taxonomy\n|  |  ├─ tags.html.twig    # Used by type \"vocabulary\" of `tags` (list of terms)\n|  |  └─ tag.html.twig     # Used by type \"term\" of `tags` (list of pages)\n|  ├─ my-layout.html.twig  # Used by pages with `layout: my-layout` in the front matter\n|  ├─ ...\n|  └─ partials             # Included templates\n|     ├─ footer.html.twig\n|     └─ ...\n└─ themes                  # Themes layouts and templates\n   └─ ...\nBuilt-in templates\nCecil comes with a set of built-in templates.\nIf you need to modify built-in templates, you can easily extract them via the following command: they will be copied in the layouts directory of your site.\nphp cecil.phar util:templates:extract\nLookup rules\nIn most of cases you don’t need to specify the layout: Cecil selects the most appropriate layout, according to the page type.\nFor example, the HTML output of home page (index.md) will be rendered:\n\nwith my-layout.html.twig if the layout variable is set to \"my-layout\" (in the front matter)\nif not, with index.html.twig if the file exists\nif not, with home.html.twig if the file exists\nif not, with list.html.twig if the file exists\n\nAll rules are detailed below, for each page type, in the priority order.\nType homepage\n\n&lt;layout&gt;.&lt;format&gt;.twig\nindex.&lt;format&gt;.twig\nhome.&lt;format&gt;.twig\nlist.&lt;format&gt;.twig\n_default\/&lt;layout&gt;.&lt;format&gt;.twig\n_default\/index.&lt;format&gt;.twig\n_default\/home.&lt;format&gt;.twig\n_default\/list.&lt;format&gt;.twig\n_default\/page.&lt;format&gt;.twig\n\nType page\n\n&lt;section&gt;\/&lt;layout&gt;.&lt;format&gt;.twig\n&lt;layout&gt;.&lt;format&gt;.twig\n&lt;section&gt;\/page.&lt;format&gt;.twig\n_default\/&lt;layout&gt;.&lt;format&gt;.twig\npage.&lt;format&gt;.twig\n_default\/page.&lt;format&gt;.twig\n\nType section\n\n&lt;layout&gt;.&lt;format&gt;.twig\n&lt;section&gt;\/index.&lt;format&gt;.twig\n&lt;section&gt;\/list.&lt;format&gt;.twig\nsection\/&lt;section&gt;.&lt;format&gt;.twig\n&lt;parent&gt;\/index.&lt;format&gt;.twig, &lt;parent&gt;\/list.&lt;format&gt;.twig and section\/&lt;parent&gt;.&lt;format&gt;.twig, for each parent section of a sub-section (nearest first)\n_default\/section.&lt;format&gt;.twig\nlist.&lt;format&gt;.twig\n_default\/list.&lt;format&gt;.twig\n\nThe &lt;section&gt; of a sub-section is its full path (e.g.: blog\/2024), and a sub-section falls back to the templates of its parent sections: if blog\/2024\/list.html.twig doesn’t exist, the sub-section blog\/2024 is rendered with blog\/list.html.twig.\nType vocabulary\n\ntaxonomy\/&lt;plural&gt;.&lt;format&gt;.twig\nvocabulary.&lt;format&gt;.twig\n_default\/vocabulary.&lt;format&gt;.twig\n\nType term\n\ntaxonomy\/&lt;plural&gt;\/&lt;term&gt;.&lt;format&gt;.twig\ntaxonomy\/&lt;singular&gt;.&lt;format&gt;.twig\nterm.&lt;format&gt;.twig\n_default\/term.&lt;format&gt;.twig\n_default\/list.&lt;format&gt;.twig\n\nThe vocabulary template is named after the plural (e.g.: taxonomy\/categories.html.twig for \/categories\/), whereas the term template is named after the singular (e.g.: taxonomy\/category.html.twig for \/categories\/data-sovereignty\/).\n&lt;term&gt; is the slugified term name: a dedicated template for the term \"Data Sovereignty\" of the categories vocabulary is taxonomy\/categories\/data-sovereignty.html.twig.\nMost of those layouts are available by default, see built-in templates.",
      "content_html": "<h1>Organization and lookup rules</h1>\n<h2 id=\"files-organization\">Files organization</h2>\n<h3 id=\"kinds-of-templates\">Kinds of templates</h3>\n<p>There are three kinds of templates: <strong><em>layouts</em></strong>, <strong><em>components</em></strong>, and <strong><em>other templates</em></strong>. <em>Layouts</em> are used to render <a href=\"../content/1-pages.md\">pages</a>, and each layout can <a href=\"https://twig.symfony.com/doc/templates.html#including-other-templates\" target=\"_blank\" rel=\"noopener noreferrer\">include templates</a> and <a href=\"4-components.md\">components</a>.</p>\n<h3 id=\"naming-convention\">Naming convention</h3>\n<p>Template files are stored in the <code translate=\"no\">layouts/</code> directory and must be named according to the following convention:</p>\n<pre><code class=\"language-plaintext hljs plaintext\" translate=\"no\">layouts/(&lt;section&gt;/)&lt;type&gt;|&lt;layout&gt;.&lt;format&gt;(.&lt;language&gt;).twig</code></pre>\n<dl>\n<dt><code translate=\"no\">&lt;section&gt;</code> (<em>optional</em>)</dt>\n<dd>The section of the page (e.g.: <code translate=\"no\">blog</code>).</dd>\n<dt><code translate=\"no\">&lt;type&gt;</code></dt>\n<dd>The page type: <code translate=\"no\">home</code> (or <code translate=\"no\">index</code>) for <em>homepage</em>, <code translate=\"no\">list</code> for <em>list</em>, <code translate=\"no\">page</code> for <em>page</em>, etc. (See <a href=\"#lookup-rules\"><em>Lookup rules</em></a> for details).</dd>\n<dt><code translate=\"no\">&lt;layout&gt;</code> (<em>optional</em>)</dt>\n<dd>The custom layout name defined in the <a href=\"../content/1-pages.md#front-matter\">front matter</a> of the page (e.g.: <code translate=\"no\">layout: my-layout</code>).</dd>\n<dt><code translate=\"no\">&lt;format&gt;</code></dt>\n<dd>The <a href=\"../configuration/8-output.md#output-formats\">output format</a> of the rendered page (e.g.: <code translate=\"no\">html</code>, <code translate=\"no\">rss</code>, <code translate=\"no\">json</code>, <code translate=\"no\">xml</code>, etc.).</dd>\n<dt><code translate=\"no\">&lt;language&gt;</code> (<em>optional</em>)</dt>\n<dd>The language of the page (e.g.: <code translate=\"no\">fr</code>).</dd>\n</dl>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-plaintext hljs plaintext\" translate=\"no\">layouts/home.html.twig       # `type` is \"homepage\"\nlayouts/page.html.twig       # `type` is \"page\"\nlayouts/page.html.fr.twig    # `type` is \"page\" and `language` is \"fr\"\nlayouts/my-layout.html.twig  # `layout` is \"my-layout\"\nlayouts/blog/list.html.twig  # `section` is \"blog\"\nlayouts/blog/list.rss.twig   # `section` is \"blog\" and `format` is \"rss\"</code></pre>\n<pre><code class=\"language-plaintext hljs plaintext\" translate=\"no\">&lt;my-site&gt;\n├─ ...\n├─ layouts\n|  ├─ index.html.twig      # Used by type \"homepage\"\n|  ├─ list.html.twig       # Used by types \"homepage\" and \"section\"\n|  ├─ list.rss.twig        # Used by types \"homepage\" and \"section\", for RSS output format\n|  ├─ page.html.twig       # Used by type \"page\"\n|  ├─ taxonomy\n|  |  ├─ tags.html.twig    # Used by type \"vocabulary\" of `tags` (list of terms)\n|  |  └─ tag.html.twig     # Used by type \"term\" of `tags` (list of pages)\n|  ├─ my-layout.html.twig  # Used by pages with `layout: my-layout` in the front matter\n|  ├─ ...\n|  └─ partials             # Included templates\n|     ├─ footer.html.twig\n|     └─ ...\n└─ themes                  # Themes layouts and templates\n   └─ ...</code></pre>\n<h3 id=\"built-in-templates\">Built-in templates</h3>\n<p>Cecil comes with a set of <a href=\"https://github.com/Cecilapp/Cecil/tree/main/resources/layouts\" target=\"_blank\" rel=\"noopener noreferrer\">built-in templates</a>.</p>\n<aside class=\"note note-tip\"><p>If you need to modify built-in templates, you can easily extract them via the following command: they will be copied in the <code translate=\"no\">layouts</code> directory of your site.</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">php cecil.phar util:templates:extract</code></pre></aside>\n<h2 id=\"lookup-rules\">Lookup rules</h2>\n<p>In most of cases <strong>you don’t need to specify the layout</strong>: Cecil selects the most appropriate layout, according to the <strong>page type</strong>.</p>\n<p>For example, the HTML output of <strong>home page</strong> (<code translate=\"no\">index.md</code>) will be rendered:</p>\n<ol>\n<li>with <code translate=\"no\">my-layout.html.twig</code> if the <code translate=\"no\">layout</code> variable is set to \"my-layout\" (in the front matter)</li>\n<li>if not, with <code translate=\"no\">index.html.twig</code> if the file exists</li>\n<li>if not, with <code translate=\"no\">home.html.twig</code> if the file exists</li>\n<li>if not, with <code translate=\"no\">list.html.twig</code> if the file exists</li>\n</ol>\n<p>All rules are detailed below, for each page type, in the priority order.</p>\n<h3 id=\"type-homepage\">Type <em>homepage</em></h3>\n<ol>\n<li><code translate=\"no\">&lt;layout&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">index.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">home.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">list.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/&lt;layout&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/index.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/home.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/list.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/page.&lt;format&gt;.twig</code></li>\n</ol>\n<h3 id=\"type-page\">Type <em>page</em></h3>\n<ol>\n<li><code translate=\"no\">&lt;section&gt;/&lt;layout&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">&lt;layout&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">&lt;section&gt;/page.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/&lt;layout&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">page.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/page.&lt;format&gt;.twig</code></li>\n</ol>\n<h3 id=\"type-section\">Type <em>section</em></h3>\n<ol>\n<li><code translate=\"no\">&lt;layout&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">&lt;section&gt;/index.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">&lt;section&gt;/list.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">section/&lt;section&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">&lt;parent&gt;/index.&lt;format&gt;.twig</code>, <code translate=\"no\">&lt;parent&gt;/list.&lt;format&gt;.twig</code> and <code translate=\"no\">section/&lt;parent&gt;.&lt;format&gt;.twig</code>, for each parent section of a sub-section (nearest first)</li>\n<li><code translate=\"no\">_default/section.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">list.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/list.&lt;format&gt;.twig</code></li>\n</ol>\n<aside class=\"note note-tip\"><p>The <code translate=\"no\">&lt;section&gt;</code> of a <a href=\"../content/1-pages.md#sub-section\">sub-section</a> is its full path (e.g.: <code translate=\"no\">blog/2024</code>), and a sub-section falls back to the templates of its parent sections: if <code translate=\"no\">blog/2024/list.html.twig</code> doesn’t exist, the sub-section <code translate=\"no\">blog/2024</code> is rendered with <code translate=\"no\">blog/list.html.twig</code>.</p></aside>\n<h3 id=\"type-vocabulary\">Type <em>vocabulary</em></h3>\n<ol>\n<li><code translate=\"no\">taxonomy/&lt;plural&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">vocabulary.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/vocabulary.&lt;format&gt;.twig</code></li>\n</ol>\n<h3 id=\"type-term\">Type <em>term</em></h3>\n<ol>\n<li><code translate=\"no\">taxonomy/&lt;plural&gt;/&lt;term&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">taxonomy/&lt;singular&gt;.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">term.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/term.&lt;format&gt;.twig</code></li>\n<li><code translate=\"no\">_default/list.&lt;format&gt;.twig</code></li>\n</ol>\n<aside class=\"note note-important\"><p>The <strong>vocabulary</strong> template is named after the <strong>plural</strong> (e.g.: <code translate=\"no\">taxonomy/categories.html.twig</code> for <code translate=\"no\">/categories/</code>), whereas the <strong>term</strong> template is named after the <strong>singular</strong> (e.g.: <code translate=\"no\">taxonomy/category.html.twig</code> for <code translate=\"no\">/categories/data-sovereignty/</code>).</p></aside>\n<aside class=\"note note-tip\"><p><code translate=\"no\">&lt;term&gt;</code> is the slugified term name: a dedicated template for the term \"Data Sovereignty\" of the <code translate=\"no\">categories</code> vocabulary is <code translate=\"no\">taxonomy/categories/data-sovereignty.html.twig</code>.</p></aside>\n<aside class=\"note note-info\"><p>Most of those layouts are available by default, see <a href=\"https://github.com/Cecilapp/Cecil/tree/main/resources/layouts\" target=\"_blank\" rel=\"noopener noreferrer\">built-in templates</a>.</p></aside>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/reference/functions/",
      "url": "https://cecil.app/documentation/templates/reference/functions/",
      "title": "Functions",
      "summary": "url, html, readtime, hash, cache_key, getenv, dump, etc.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Functions\n\nFunctions can be called to generate content. Functions are called by their name followed by parentheses (()) and may have arguments.\n\nurl\nCreates a valid URL for a page, a menu entry, an asset, a page ID or a path.\n{{ url(value, {options}) }}\n\n\n\nOption\nDescription\nType\nDefault\n\n\n\n\ncanonical\nPrefix URL with baseurl or use canonical.url if exists.\nboolean\nfalse\n\n\nformat\nDefines page output format (e.g.: json).\nstring\nhtml\n\n\nlanguage\nDefines page language (e.g.: fr).\nstring\nnull\n\n\n\nExamples:\n{# page #}\n{{ url(page) }}\n{{ url(page, {canonical: true}) }}\n{{ url(page, {format: json}) }}\n{{ url(page, {language: fr}) }}\n{# menu entry #}\n{{ url(site.menus.main.about) }}\n{# asset #}\n{{ url(asset('styles.css')) }}\n{# page ID #}\n{{ url('page-id') }}\n{# path #}\n{{ url('about-me\/') }}\n{{ url('tags\/' ~ tag) }}\nFor convenience the url function is also available as a filter:\n{# page #}\n{{ page|url }}\n{{ page|url({canonical: true, format: json, language: fr}) }}\n{# asset #}\n{{ asset('styles.css')|url }}\nWhen the value is a string, url() slugifies it to find a matching page ID (e.g.: url('tags\/My Tag') returns the URL of the page tags\/my-tag). If no page matches, the string is kept as a path, with invalid characters (e.g.: spaces) percent-encoded.\nhtml\nCreates an HTML element from an asset (or an array of assets with custom attributes).\n{{ html(asset, {attributes}, {options}) }}\n{# dedicated functions for each common type of asset #}\n{{ css(asset) }}\n{{ js(asset) }}\n{{ image(asset) }}\n{{ audio(asset) }}\n{{ video(asset) }}\n\n\n\nOption\nDescription\nType\n\n\n\n\nattributes\nAdds name=\"value\" couple to the HTML element.\narray\n\n\noptions\n{preload: boolean}: preloads.For images:{formats: array}: adds alternative formats.{responsive: bool|string}: adds responsive images (based on width or pixels density).{placeholder: string}: fills the image background before loading (color or lqip).\narray\n\n\n\nSince version 8.42.0, the html function replace the deprecated html filter.\nYou can define a global default behavior of images options (formats, responsive and placeholder) through the layouts configuration.\nWhen layouts.images.dark_suffix is configured (e.g. .dark), Cecil automatically looks for a dark variant of each image (e.g. photo.dark.jpg alongside photo.jpg) and generates a &lt;picture&gt; element with a &lt;source media=\"(prefers-color-scheme: dark)\"&gt;.\nIn the same way, when layouts.images.mobile_suffix is configured (e.g. .mobile), Cecil looks for a mobile variant of each image (e.g. photo.mobile.jpg) and adds a &lt;source&gt; with the layouts.images.mobile_media_query media query. If a dark variant of the mobile image exists (e.g. photo.mobile.dark.jpg), it is used on mobile with dark color scheme.\nExamples:\n{# CSS with an attribute #}\n{{ html(asset('print.css'), {media: 'print'}) }}\n{# CSS with an attribute and an option #}\n{{ html(asset('styles.css'), {title: 'Main theme'}, {preload: true}) }}\n{# Array of assets with media query #}\n{{ html([\n  {asset: asset('css\/style.css')},\n  {asset: asset('css\/style-dark.css'), attributes: {media: '(prefers-color-scheme: dark)'}}\n]) }}\n{# JavaScript #}\n{{ html(asset('script.js')) }}\n{# image without specific attributes nor options #}\n{{ html(asset('image.png')) }}\n{# image with specific attributes, responsive images and alternative formats #}\n{{ html(asset('image.jpg'), {alt: 'Description', loading: 'lazy'}, {responsive: true, formats: ['avif', 'webp']}) }}\n{# image with responsive pixels density images #}\n{{ html(asset('image.jpg'), options={responsive: 'density'}, attributes={width: 256}) }}\n{# image with a Low-Quality Image Placeholder #}\n{{ html(asset('image.jpg'), {alt: 'Description', loading: 'lazy'}, {placeholder: 'lqip'}) }}\n{# Audio #}\n{{ html(asset('audio.mp3')) }}\n{# Video #}\n{{ html(asset('video.mp4')) }}\nFor convenience the html function stay available as a filter (but is considered as deprecated):\n{{ asset|html({attributes}, {options}) }}\nreadtime\nDetermines read time of a text, in minutes.\n{{ readtime(value) }}\nExample:\n{{ readtime(page.content) }} min\nhash\nCalculates the hash of an object, an array or a string with a given algorithm.\n{{ hash(value, algorithm) }}\nalgorithm can be any algorithm supported by PHP's hash() function (e.g.: md5, sha256, etc.). Default is xxh128.\nExample:\n{{ hash('my string', 'sha256') }}\ncache_key\nCalculates a cache key for fragments cache based on a name and an optional value.\n{% cache cache_key(name, value) %}\n  {# cacheable content #}\n{% endcache %}\nThe function adds a hash of the value (could be a string, an array or an object) to the name (and the current language and build ID to be sure the generated cache key is unique) so if the value is changed the cache key is changed too and the cache is automatically cleared.\ngetenv\nGets the value of an environment variable from its key.\n{{ getenv(var) }}\nExample:\n{{ getenv('VAR') }}\ndump\nThe dump function dumps information about a template variable. This is mostly useful to debug a template that does not behave as expected by introspecting its variables:\n{{ dump(user) }}\nThe debug mode must be enabled.\nd\nThe d() function is the HTML version of dump() and use the Symfony VarDumper Component behind the scenes.\n{{ d(variable, {theme: light}) }}\n\nIf variable is not provided then the function returns the current Twig context\nAvailable themes are « light » (default) and « dark »\n\nThe debug mode must be enabled.",
      "content_html": "<h1>Functions</h1>\n<blockquote>\n<p><a href=\"https://twig.symfony.com/doc/functions/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">Functions</a> can be called to generate content. Functions are called by their name followed by parentheses (<code translate=\"no\">()</code>) and may have arguments.</p>\n</blockquote>\n<h2 id=\"url\">url</h2>\n<p>Creates a valid URL for a page, a menu entry, an asset, a page ID or a path.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ url(value, {options}) }}</span></code></pre>\n<table>\n<thead>\n<tr>\n<th>Option</th>\n<th>Description</th>\n<th>Type</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>canonical</td>\n<td>Prefix URL with <a href=\"../../configuration/1-site.md#baseurl\"><code translate=\"no\">baseurl</code></a> or use <a href=\"../../configuration/1-site.md#metatags-options\"><code translate=\"no\">canonical.url</code></a> if exists.</td>\n<td>boolean</td>\n<td><code translate=\"no\">false</code></td>\n</tr>\n<tr>\n<td>format</td>\n<td>Defines page <a href=\"../../configuration/8-output.md#output-formats\">output format</a> (e.g.: <code translate=\"no\">json</code>).</td>\n<td>string</td>\n<td><code translate=\"no\">html</code></td>\n</tr>\n<tr>\n<td>language</td>\n<td>Defines page <a href=\"../../configuration/2-languages.md#language\">language</a> (e.g.: <code translate=\"no\">fr</code>).</td>\n<td>string</td>\n<td>null</td>\n</tr>\n</tbody>\n</table>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# page #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url(page) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url(page, {canonical: true}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url(page, {format: json}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url(page, {language: fr}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# menu entry #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url(site.menus.main.about) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# asset #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url(asset('styles.css')) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# page ID #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url('page-id') }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# path #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url('about-me/') }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ url('tags/' ~ tag) }}</span></code></pre>\n<aside class=\"note note-info\"><p>For convenience the <code translate=\"no\">url</code> function is also available as a filter:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# page #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ page|url }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ page|url({canonical: true, format: json, language: fr}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# asset #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ asset('styles.css')|url }}</span></code></pre></aside>\n<aside class=\"note note-tip\"><p>When the value is a string, <code translate=\"no\">url()</code> slugifies it to find a matching page ID (e.g.: <code translate=\"no\">url('tags/My Tag')</code> returns the URL of the page <code translate=\"no\">tags/my-tag</code>). If no page matches, the string is kept as a path, with invalid characters (e.g.: spaces) percent-encoded.</p></aside>\n<h2 id=\"html\">html</h2>\n<p>Creates an HTML element from an asset (or an array of assets with custom attributes).</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ html(asset, {attributes}, {options}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# dedicated functions for each common type of asset #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ css(asset) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ js(asset) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ image(asset) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ audio(asset) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ video(asset) }}</span></code></pre>\n<table>\n<thead>\n<tr>\n<th>Option</th>\n<th>Description</th>\n<th>Type</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>attributes</td>\n<td>Adds <code translate=\"no\">name=\"value\"</code> couple to the HTML element.</td>\n<td>array</td>\n</tr>\n<tr>\n<td>options</td>\n<td><code translate=\"no\">{preload: boolean}</code>: preloads.<br>For images:<br><code translate=\"no\">{formats: array}</code>: adds alternative formats.<br><code translate=\"no\">{responsive: bool|string}</code>: adds responsive images (based on <code translate=\"no\">width</code> or pixels <code translate=\"no\">density</code>).<br><code translate=\"no\">{placeholder: string}</code>: fills the image background before loading (<code translate=\"no\">color</code> or <code translate=\"no\">lqip</code>).</td>\n<td>array</td>\n</tr>\n</tbody>\n</table>\n<aside class=\"note note-warning\"><p>Since version <ins>8.42.0</ins>, the <code translate=\"no\">html</code> function replace the deprecated <code translate=\"no\">html</code> filter.</p></aside>\n<aside class=\"note note-tip\"><p>You can define a global default behavior of images options (<code translate=\"no\">formats</code>, <code translate=\"no\">responsive</code> and <code translate=\"no\">placeholder</code>) through the <a href=\"../../configuration/7-layouts.md#layouts-images\">layouts configuration</a>.</p>\n<p>When <a href=\"../../configuration/7-layouts.md#layouts-images\"><code translate=\"no\">layouts.images.dark_suffix</code></a> is configured (e.g. <code translate=\"no\">.dark</code>), Cecil automatically looks for a dark variant of each image (e.g. <code translate=\"no\">photo.dark.jpg</code> alongside <code translate=\"no\">photo.jpg</code>) and generates a <code translate=\"no\">&lt;picture&gt;</code> element with a <code translate=\"no\">&lt;source media=\"(prefers-color-scheme: dark)\"&gt;</code>.</p>\n<p>In the same way, when <a href=\"../../configuration/7-layouts.md#layouts-images\"><code translate=\"no\">layouts.images.mobile_suffix</code></a> is configured (e.g. <code translate=\"no\">.mobile</code>), Cecil looks for a mobile variant of each image (e.g. <code translate=\"no\">photo.mobile.jpg</code>) and adds a <code translate=\"no\">&lt;source&gt;</code> with the <a href=\"../../configuration/7-layouts.md#layouts-images\"><code translate=\"no\">layouts.images.mobile_media_query</code></a> media query. If a dark variant of the mobile image exists (e.g. <code translate=\"no\">photo.mobile.dark.jpg</code>), it is used on mobile with dark color scheme.</p></aside>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# CSS with an attribute #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('print.css'), {media: 'print'}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# CSS with an attribute and an option #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('styles.css'), {title: 'Main theme'}, {preload: true}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# Array of assets with media query #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html([\n  {asset: asset('css/style.css')},\n  {asset: asset('css/style-dark.css'), attributes: {media: '(prefers-color-scheme: dark)'}}</span><span class=\"xml\">\n]) }}\n</span><span class=\"hljs-comment\">{# JavaScript #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('script.js')) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# image without specific attributes nor options #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('image.png')) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# image with specific attributes, responsive images and alternative formats #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('image.jpg'), {alt: 'Description', loading: 'lazy'}, {responsive: true, formats: ['avif', 'webp']}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# image with responsive pixels density images #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('image.jpg'), options={responsive: 'density'}, attributes={width: 256}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# image with a Low-Quality Image Placeholder #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('image.jpg'), {alt: 'Description', loading: 'lazy'}, {placeholder: 'lqip'}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# Audio #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('audio.mp3')) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# Video #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ html(asset('video.mp4')) }}</span></code></pre>\n<aside class=\"note note-info\"><p>For convenience the <code translate=\"no\">html</code> function stay available as a filter (but is considered as deprecated):</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ asset|html({attributes}, {options}) }}</span></code></pre></aside>\n<h2 id=\"readtime\">readtime</h2>\n<p>Determines read time of a text, in minutes.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ readtime(value) }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ readtime(page.content) }}</span><span class=\"xml\"> min</span></code></pre>\n<h2 id=\"hash\">hash</h2>\n<p>Calculates the hash of an object, an array or a string with a given algorithm.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ hash(value, algorithm) }}</span></code></pre>\n<p><code translate=\"no\">algorithm</code> can be any algorithm supported by PHP's <code translate=\"no\">hash()</code> function (e.g.: <code translate=\"no\">md5</code>, <code translate=\"no\">sha256</code>, etc.). Default is <code translate=\"no\">xxh128</code>.</p>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ hash('my string', 'sha256') }}</span></code></pre>\n<h2 id=\"cache-key\">cache_key</h2>\n<p>Calculates a cache key for <a href=\"../6-cache.md#fragments-cache\"><em>fragments</em> cache</a> based on a name and an optional value.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">cache</span> cache_key(name, value) %}</span><span class=\"xml\">\n  </span><span class=\"hljs-comment\">{# cacheable content #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endcache</span> %}</span></code></pre>\n<p>The function adds a hash of the value (could be a string, an array or an object) to the name (and the current language and build ID to be sure the generated cache key is unique) so if the value is changed the cache key is changed too and the cache is automatically cleared.</p>\n<h2 id=\"getenv\">getenv</h2>\n<p>Gets the value of an environment variable from its key.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ getenv(var) }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ getenv('VAR') }}</span></code></pre>\n<h2 id=\"dump\">dump</h2>\n<p>The <code translate=\"no\">dump</code> function dumps information about a template variable. This is mostly useful to debug a template that does not behave as expected by introspecting its variables:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ <span class=\"hljs-name\">dump</span><span class=\"hljs-params\">(user)</span> }}</span></code></pre>\n<aside class=\"note note-important\"><p>The <a href=\"../../configuration/1-site.md#debug\"><em>debug mode</em></a> must be enabled.</p></aside>\n<h2 id=\"d\">d</h2>\n<p>The <code translate=\"no\">d()</code> function is the HTML version of <a href=\"#dump\"><code translate=\"no\">dump()</code></a> and use the <a href=\"https://symfony.com/doc/5.4/components/var_dumper.html\" target=\"_blank\" rel=\"noopener noreferrer\">Symfony VarDumper Component</a> behind the scenes.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ d(variable, {theme: light}) }}</span></code></pre>\n<ul>\n<li>If <em>variable</em> is not provided then the function returns the current Twig context</li>\n<li>Available themes are « light » (default) and « dark »</li>\n</ul>\n<aside class=\"note note-important\"><p>The <a href=\"../../configuration/1-site.md#debug\"><em>debug mode</em></a> must be enabled.</p></aside>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/variables/",
      "url": "https://cecil.app/documentation/templates/variables/",
      "title": "Variables",
      "summary": "Variables available in templates: site, page and cecil.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-06T00:00:00+00:00","content_text": "Variables\n\nThe application passes variables to the templates for manipulation in the template. Variables may have attributes or elements you can access, too.\nUse a dot (.) to access attributes of a variable: {{ foo.bar }}\n\nYou can use variables from different scopes: site, page, cecil.\nsite\nThe site variable contains built-in variables and those set in the configuration.\n\n\n\nVariable\nDescription\n\n\n\n\nsite.pages\nCollection of all pages, in the current language.\n\n\nsite.allpages\nCollection of all pages, in all languages.\n\n\nsite.page(id)\nA page with the given ID.\n\n\nsite.taxonomies\nCollection of vocabularies.\n\n\nsite.home\nID of the home page.\n\n\nsite.time\nCurrent Timestamp.\n\n\nsite.debug\nDebug mode status (true or false).\n\n\nsite.build\nCurrent build ID.\n\n\n\nExample:\ntitle: \"My amazing website!\"\nCan be displayed in a template with:\n{{ site.title }}\nUse showable method on pages collection to return only published and not virtual\/redirect\/excluded pages.\nExample:\n{% for page in site.pages.showable %}\n  &lt;a href=\"{{ url(page) }}\"&gt;{{ page.title }}&lt;\/a&gt;\n{% endfor %}\nIn some cases, you can encounter conflicts between configuration and built-in variables (e.g. pages.default configuration). In that case, you can use config.&lt;variable&gt; (where &lt;variable&gt; is the variable name\/path) to access the raw configuration directly.\nExample:\n{{ config.pages.default.sitemap.priority }}\nsite.menus\nLoop on site.menus.&lt;menu&gt; to get each entry of the &lt;menu&gt; collection (e.g.: main).\n\n\n\nVariable\nDescription\n\n\n\n\n&lt;entry&gt;.name\nEntry name.\n\n\n&lt;entry&gt;.url\nEntry URL.\n\n\n&lt;entry&gt;.weight\nEntry weight (useful to sort menu entries).\n\n\n\nExample:\n&lt;nav&gt;\n  &lt;ol&gt;\n  {% for entry in site.menus.main|sort_by_weight %}\n    &lt;li&gt;&lt;a href=\"{{ url(entry.url) }}\" data-weight=\"{{ entry.weight }}\"&gt;{{ entry.name }}&lt;\/a&gt;&lt;\/li&gt;\n  {% endfor %}\n  &lt;\/ol&gt;\n&lt;\/nav&gt;\nsite.language\nInformation about the current language.\n\n\n\nVariable\nDescription\n\n\n\n\nsite.language\nLanguage code (e.g.: en).\n\n\nsite.language.name\nLanguage name (e.g.: English).\n\n\nsite.language.locale\nLanguage locale code (e.g.: en_US).\n\n\nsite.language.weight\nLanguage position in the languages list.\n\n\n\nYou can retrieve name, locale and weight of a specific language by passing its code as a parameter.\ne.g.: site.language.name('fr').\nsite.static\nThe static files collection can be accessed via site.static if the static load is enabled.\nEach file exposes the following properties:\n\npath: relative path (e.g.: \/images\/img-1.jpg)\ndate: creation date (timestamp)\nupdated: modification date (timestamp)\nname: name (e.g.: img-1.jpg)\nbasename: name without extension (e.g.: img-1)\next: extension (e.g.: jpg)\ntype: media type (e.g.: image)\nsubtype: media sub type (e.g.: image\/jpeg)\nexif: image EXIF data (array)\naudio: Mp3Info object\nvideo: array of basic video information (duration in seconds, width and height)\n\nsite.data\nA data collection can be accessed via site.data.&lt;filename&gt; (without file extension).\nExamples:\n\ndata\/authors.yml : site.data.authors\ndata\/authors.fr.yml : site.data.authors (if site.language = \"fr\")\ndata\/galleries\/gallery-1.json : site.data.galleries['gallery-1']\n\npage\nThe page variable contains built-in variables of a page and those set in the front matter.\n\n\n\nVariable\nDescription\nExample\n\n\n\n\npage.id\nUnique identifier.\nblog\/post-1\n\n\npage.title\nFile name (without extension).\nPost 1\n\n\npage.date\nFile creation date.\nDateTime\n\n\npage.body\nFile body.\nMarkdown\n\n\npage.content\nFile body converted in HTML.\nHTML\n\n\npage.section\nFile root folder (slugified).\nblog\n\n\npage.path\nFile path (slugified).\nblog\/post-1\n\n\npage.slug\nFile name (slugified).\npost-1\n\n\npage.filepath\nFile system path.\nBlog\/Post 1.md\n\n\npage.type\nhomepage, page, section, vocabulary or term.\npage\n\n\npage.pages\nCollection of all sub pages.\nCollection\n\n\npage.translations\nCollection of translated pages.\nCollection\n\n\n\nUse showable method on pages collection to return only published and not virtual\/redirect\/excluded pages.\nExample:\n{% for page in page.pages.showable %}\n  &lt;a href=\"{{ url(page) }}\"&gt;{{ page.title }}&lt;\/a&gt;\n{% endfor %}\nNested sections\nIn a nested sections context, page.parent, page.ancestors, page.sections and page.toplevel help you build navigation.\n\n\n\nVariable\nDescription\nExample\n\n\n\n\npage.parent\nParent section's page (null if none).\nPage\n\n\npage.ancestors\nCollection of ancestor sections (nearest first).\nCollection\n\n\npage.sections\nCollection of immediate descendant sections.\nCollection\n\n\npage.toplevel\ntrue if the page is a top level section.\nBoolean\n\n\n\nBreadcrumb (from the home page to the current page):\n&lt;nav aria-label=\"breadcrumb\"&gt;\n  &lt;ul&gt;\n    &lt;li&gt;&lt;a href=\"{{ url(site.home) }}\"&gt;{{ site.title }}&lt;\/a&gt;&lt;\/li&gt;\n    {% for section in page.ancestors|reverse %}\n    &lt;li&gt;&lt;a href=\"{{ url(section) }}\"&gt;{{ section.title }}&lt;\/a&gt;&lt;\/li&gt;\n    {% endfor %}\n    {% if page.id != site.home %}\n    &lt;li&gt;&lt;a href=\"{{ url(page) }}\" aria-current=\"page\"&gt;{{ page.title }}&lt;\/a&gt;&lt;\/li&gt;\n    {% endif %}\n  &lt;\/ul&gt;\n&lt;\/nav&gt;\nA ready-to-use breadcrumb.html.twig partial is available:\n{{ include('partials\/breadcrumb.html.twig') }}\nSub-sections menu (immediate descendant sections of the current section):\n{% if page.sections|length %}\n&lt;ul&gt;\n  {% for section in page.sections|sort_by_title %}\n  &lt;li&gt;&lt;a href=\"{{ url(section) }}\"&gt;{{ section.title }}&lt;\/a&gt;&lt;\/li&gt;\n  {% endfor %}\n&lt;\/ul&gt;\n{% endif %}\nMain navigation limited to top level sections (from any page):\n&lt;nav&gt;\n  {% for section in site.page(site.home).sections|sort_by_title %}\n  &lt;a href=\"{{ url(section) }}\"&gt;{{ section.title }}&lt;\/a&gt;\n  {% endfor %}\n&lt;\/nav&gt;\nLink to the parent section:\n{% if page.parent %}\n&lt;a href=\"{{ url(page.parent) }}\"&gt;← {{ page.parent.title }}&lt;\/a&gt;\n{% endif %}\npage.&lt;prev\/next&gt;\nNavigation between pages within the same section, sorted according to the section's sortby (chronological order for dates).\nWith sub-sections, navigation follows the sections tree: the pages of a top level Section and of all its sub-sections are chained, each sub-section (its index page) being placed among the pages of its parent Section and followed by its own pages.\n\n\n\nVariable\nDescription\nExample\n\n\n\n\npage.prev\nPrevious page.\nPage\n\n\npage.next\nNext page.\nPage\n\n\n\nExample:\n&lt;a href=\"{{ url(page.prev) }}\"&gt;{{ page.prev.title }}&lt;\/a&gt;\npage.paginator\nPaginator helps you build navigation for list pages: homepage, sections, and taxonomies.\n\n\n\nVariable\nDescription\n\n\n\n\npage.paginator.pages\nPages Collection.\n\n\npage.paginator.pages_total\nNumber total of pages.\n\n\npage.paginator.count\nNumber of paginator's pages.\n\n\npage.paginator.current\nPosition index of the current page.\n\n\npage.paginator.links.first\nPage ID of the first page.\n\n\npage.paginator.links.prev\nPage ID of the previous page.\n\n\npage.paginator.links.self\nPage ID of the current page.\n\n\npage.paginator.links.next\nPage ID of the next page.\n\n\npage.paginator.links.last\nPage ID of the last page.\n\n\npage.paginator.links.path\nPage ID without the position index.\n\n\n\nBecause links entries are Page ID you must use the url() function to create working links.\ne.g: {{ url(page.paginator.links.next) }}\nExample:\n{% if page.paginator %}\n&lt;div&gt;\n  {% if page.paginator.links.prev is defined %}\n  &lt;a href=\"{{ url(page.paginator.links.prev) }}\"&gt;Previous&lt;\/a&gt;\n  {% endif %}\n  {% if page.paginator.links.next is defined %}\n  &lt;a href=\"{{ url(page.paginator.links.next) }}\"&gt;Next&lt;\/a&gt;\n  {% endif %}\n&lt;\/div&gt;\n{% endif %}\nExample:\n{% if page.paginator %}\n&lt;div&gt;\n  {% for paginator_index in 1..page.paginator.count %}\n    {% if paginator_index != page.paginator.current %}\n      {% if paginator_index == 1 %}\n  &lt;a href=\"{{ url(page.paginator.links.first) }}\"&gt;{{ paginator_index }}&lt;\/a&gt;\n      {% else %}\n  &lt;a href=\"{{ url(page.paginator.links.path ~ '\/' ~ paginator_index) }}\"&gt;{{ paginator_index }}&lt;\/a&gt;\n      {% endif %}\n    {% else %}\n  {{ paginator_index }}\n    {% endif %}\n  {% endfor %}\n&lt;\/div&gt;\n{% endif %}\nTaxonomy\nVariables available in vocabulary and term templates.\nVocabulary\nPage \/&lt;plural&gt;\/ (e.g.: \/categories\/).\n\n\n\nVariable\nDescription\n\n\n\n\npage.plural\nVocabulary name in plural form.\n\n\npage.singular\nVocabulary name in singular form.\n\n\npage.terms\nList of terms (Collection).\n\n\n\nEach term of page.terms provides term.id (term ID, e.g.: categories\/php), term.name (term name, e.g.: PHP) and the number of its pages with term|length.\nTerm\nPage \/&lt;plural&gt;\/&lt;term&gt;\/ (e.g.: \/categories\/php\/).\n\n\n\nVariable\nDescription\n\n\n\n\npage.title\nTerm name.\n\n\npage.term\nTerm ID (e.g.: categories\/php).\n\n\npage.plural\nVocabulary name in plural form.\n\n\npage.singular\nVocabulary name in singular form.\n\n\npage.pages\nList of pages in this term, sorted by date (Collection).\n\n\n\nTaxonomy example\nConfiguration:\ntaxonomies:\n  categories: category\nPage front matter:\n---\ncategories: [\"Data Sovereignty\"]\n---\nList of terms (\/categories\/), in layouts\/taxonomy\/categories.html.twig:\n{% extends 'page.html.twig' %}\n\n{% block content %}\n  &lt;h1&gt;{{ page.title }}&lt;\/h1&gt;\n  &lt;ul&gt;\n  {% for term in page.terms %}\n    &lt;li&gt;&lt;a href=\"{{ url(term.id) }}\"&gt;{{ term.name }}&lt;\/a&gt; ({{ term|length }})&lt;\/li&gt;\n  {% endfor %}\n  &lt;\/ul&gt;\n{% endblock %}\nList of pages of a term (\/categories\/data-sovereignty\/), in layouts\/taxonomy\/category.html.twig:\n{% extends 'page.html.twig' %}\n\n{% block content %}\n  &lt;h1&gt;{{ page.title }}&lt;\/h1&gt;\n  {% for p in page.paginator.pages ?? page.pages %}\n    &lt;article&gt;\n      &lt;h2&gt;&lt;a href=\"{{ url(p) }}\"&gt;{{ p.title }}&lt;\/a&gt;&lt;\/h2&gt;\n    &lt;\/article&gt;\n  {% endfor %}\n  &lt;a href=\"{{ url(page.plural) }}\"&gt;All {{ page.plural }}&lt;\/a&gt;\n{% endblock %}\nLinks to the terms of the current page, in a page template:\n{% for category in page.categories ?? [] %}\n  &lt;a href=\"{{ url('categories\/' ~ category) }}\"&gt;{{ category }}&lt;\/a&gt;\n{% endfor %}\nThe url() function slugifies the given string to find the matching page: url('categories\/Data Sovereignty') returns \/categories\/data-sovereignty\/.\nYou can also use the built-in partial {{ include('partials\/terms-list.html.twig', {vocabulary: 'categories'}) }}.\ncecil\n\n\n\nVariable\nDescription\n\n\n\n\ncecil.url\nURL of the Cecil website.\n\n\ncecil.version\nCecil current version.\n\n\ncecil.poweredby\nPrint Cecil v%s, with %s is the current version.\n\n\n",
      "content_html": "<h1>Variables</h1>\n<blockquote>\n<p>The application passes variables to the templates for manipulation in the template. Variables may have attributes or elements you can access, too.<br>\nUse a dot (.) to access attributes of a variable: <code translate=\"no\">{{ foo.bar }}</code></p>\n</blockquote>\n<p>You can use variables from different scopes: <a href=\"#site\"><code translate=\"no\">site</code></a>, <a href=\"#page\"><code translate=\"no\">page</code></a>, <a href=\"#cecil\"><code translate=\"no\">cecil</code></a>.</p>\n<h2 id=\"site\">site</h2>\n<p>The <code translate=\"no\">site</code> variable contains built-in variables <strong>and</strong> those set in the <a href=\"../configuration/index.md\">configuration</a>.</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">site.pages</code></td>\n<td>Collection of all pages, in the current language.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.allpages</code></td>\n<td>Collection of all pages, in all languages.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.page(id)</code></td>\n<td>A page with the given ID.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.taxonomies</code></td>\n<td>Collection of vocabularies.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.home</code></td>\n<td>ID of the home page.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.time</code></td>\n<td>Current <a href=\"https://wikipedia.org/wiki/Unix_time\" target=\"_blank\" rel=\"noopener noreferrer\"><em>Timestamp</em></a>.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.debug</code></td>\n<td>Debug mode status (<code translate=\"no\">true</code> or <code translate=\"no\">false</code>).</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.build</code></td>\n<td>Current build ID.</td>\n</tr>\n</tbody>\n</table>\n<p><em>Example:</em></p>\n<pre><code class=\"language-yaml hljs yaml\" translate=\"no\"><span class=\"hljs-attr\">title:</span> <span class=\"hljs-string\">\"My amazing website!\"</span></code></pre>\n<p>Can be displayed in a template with:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ site.title }}</span></code></pre>\n<aside class=\"note note-important\"><p>Use <code translate=\"no\">showable</code> method on pages collection to return only published and not <em>virtual/redirect/excluded</em> pages.</p>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> page in site.pages.showable %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ page.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span></code></pre></aside>\n<aside class=\"note note-warning\"><p>In some cases, you can encounter conflicts between configuration and built-in variables (e.g. <code translate=\"no\">pages.default</code> configuration). In that case, you can use <code translate=\"no\">config.&lt;variable&gt;</code> (where <code translate=\"no\">&lt;variable&gt;</code> is the variable name/path) to access the raw configuration directly.</p>\n<p>Example:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ config.pages.default.sitemap.priority }}</span></code></pre></aside>\n<h3 id=\"site-menus\">site.menus</h3>\n<p>Loop on <code translate=\"no\">site.menus.&lt;menu&gt;</code> to get each entry of the <code translate=\"no\">&lt;menu&gt;</code> collection (e.g.: <code translate=\"no\">main</code>).</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">&lt;entry&gt;.name</code></td>\n<td>Entry name.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">&lt;entry&gt;.url</code></td>\n<td>Entry URL.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">&lt;entry&gt;.weight</code></td>\n<td>Entry weight (useful to sort menu entries).</td>\n</tr>\n</tbody>\n</table>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">nav</span>&gt;</span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ol</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> entry in site.menus.main|sort_by_weight %}</span><span class=\"xml\">\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li</span>&gt;</span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(entry.url) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span> <span class=\"hljs-attr\">data-weight</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ entry.weight }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ entry.name }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">li</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">ol</span>&gt;</span>\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">nav</span>&gt;</span></span></code></pre>\n<h3 id=\"site-language\">site.language</h3>\n<p>Information about the current language.</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">site.language</code></td>\n<td>Language code (e.g.: <code translate=\"no\">en</code>).</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.language.name</code></td>\n<td>Language name (e.g.: <code translate=\"no\">English</code>).</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.language.locale</code></td>\n<td>Language <a href=\"../configuration/3-locale-codes.md\">locale code</a> (e.g.: <code translate=\"no\">en_US</code>).</td>\n</tr>\n<tr>\n<td><code translate=\"no\">site.language.weight</code></td>\n<td>Language position in the <code translate=\"no\">languages</code> list.</td>\n</tr>\n</tbody>\n</table>\n<aside class=\"note note-tip\"><p>You can retrieve <code translate=\"no\">name</code>, <code translate=\"no\">locale</code> and <code translate=\"no\">weight</code> of a specific language by passing its code as a parameter.<br>\ne.g.: <code translate=\"no\">site.language.name('fr')</code>.</p></aside>\n<h3 id=\"site-static\">site.static</h3>\n<p>The static files collection can be accessed via <code translate=\"no\">site.static</code> if the <a href=\"../configuration/5-data-static.md#static-load\"><em>static load</em></a> is enabled.</p>\n<p>Each file exposes the following properties:</p>\n<ul>\n<li><code translate=\"no\">path</code>: relative path (e.g.: <code translate=\"no\">/images/img-1.jpg</code>)</li>\n<li><code translate=\"no\">date</code>: creation date (<em>timestamp</em>)</li>\n<li><code translate=\"no\">updated</code>: modification date (<em>timestamp</em>)</li>\n<li><code translate=\"no\">name</code>: name (e.g.: <code translate=\"no\">img-1.jpg</code>)</li>\n<li><code translate=\"no\">basename</code>: name without extension (e.g.: <code translate=\"no\">img-1</code>)</li>\n<li><code translate=\"no\">ext</code>: extension (e.g.: <code translate=\"no\">jpg</code>)</li>\n<li><code translate=\"no\">type</code>: media type (e.g.: <code translate=\"no\">image</code>)</li>\n<li><code translate=\"no\">subtype</code>: media sub type (e.g.: <code translate=\"no\">image/jpeg</code>)</li>\n<li><code translate=\"no\">exif</code>: image EXIF data (<em>array</em>)</li>\n<li><code translate=\"no\">audio</code>: <a href=\"https://github.com/wapmorgan/Mp3Info#audio-information\" target=\"_blank\" rel=\"noopener noreferrer\">Mp3Info</a> object</li>\n<li><code translate=\"no\">video</code>: array of basic video information (duration in seconds, width and height)</li>\n</ul>\n<h3 id=\"site-data\">site.data</h3>\n<p>A data collection can be accessed via <code translate=\"no\">site.data.&lt;filename&gt;</code> (without file extension).</p>\n<p><em>Examples:</em></p>\n<ul>\n<li><code translate=\"no\">data/authors.yml</code> : <code translate=\"no\">site.data.authors</code></li>\n<li><code translate=\"no\">data/authors.fr.yml</code> : <code translate=\"no\">site.data.authors</code> (if <code translate=\"no\">site.language</code> = \"fr\")</li>\n<li><code translate=\"no\">data/galleries/gallery-1.json</code> : <code translate=\"no\">site.data.galleries['gallery-1']</code></li>\n</ul>\n<h2 id=\"page\">page</h2>\n<p>The <code translate=\"no\">page</code> variable contains built-in variables of a page <strong>and</strong> those set in the <a href=\"../content/1-pages.md#front-matter\">front matter</a>.</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n<th>Example</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">page.id</code></td>\n<td>Unique identifier.</td>\n<td><code translate=\"no\">blog/post-1</code></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.title</code></td>\n<td>File name (without extension).</td>\n<td><code translate=\"no\">Post 1</code></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.date</code></td>\n<td>File creation date.</td>\n<td><em>DateTime</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.body</code></td>\n<td>File body.</td>\n<td><em>Markdown</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.content</code></td>\n<td>File body converted in HTML.</td>\n<td><em>HTML</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.section</code></td>\n<td>File root folder (<em>slugified</em>).</td>\n<td><code translate=\"no\">blog</code></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.path</code></td>\n<td>File path (<em>slugified</em>).</td>\n<td><code translate=\"no\">blog/post-1</code></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.slug</code></td>\n<td>File name (<em>slugified</em>).</td>\n<td><code translate=\"no\">post-1</code></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.filepath</code></td>\n<td>File system path.</td>\n<td><code translate=\"no\">Blog/Post 1.md</code></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.type</code></td>\n<td><code translate=\"no\">homepage</code>, <code translate=\"no\">page</code>, <code translate=\"no\">section</code>, <code translate=\"no\">vocabulary</code> or <code translate=\"no\">term</code>.</td>\n<td><code translate=\"no\">page</code></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.pages</code></td>\n<td>Collection of all sub pages.</td>\n<td><em>Collection</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.translations</code></td>\n<td>Collection of translated pages.</td>\n<td><em>Collection</em></td>\n</tr>\n</tbody>\n</table>\n<aside class=\"note note-important\"><p>Use <code translate=\"no\">showable</code> method on pages collection to return only published and not <em>virtual/redirect/excluded</em> pages.</p>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> page in page.pages.showable %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ page.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span></code></pre></aside>\n<h3 id=\"nested-sections\">Nested sections</h3>\n<p>In a <a href=\"../content/1-pages.md#sub-section\">nested sections</a> context, <code translate=\"no\">page.parent</code>, <code translate=\"no\">page.ancestors</code>, <code translate=\"no\">page.sections</code> and <code translate=\"no\">page.toplevel</code> help you build navigation.</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n<th>Example</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">page.parent</code></td>\n<td>Parent <em>section</em>'s page (<code translate=\"no\">null</code> if none).</td>\n<td><em>Page</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.ancestors</code></td>\n<td>Collection of ancestor <em>sections</em> (nearest first).</td>\n<td><em>Collection</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.sections</code></td>\n<td>Collection of immediate descendant <em>sections</em>.</td>\n<td><em>Collection</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.toplevel</code></td>\n<td><code translate=\"no\">true</code> if the page is a top level <em>section</em>.</td>\n<td><em>Boolean</em></td>\n</tr>\n</tbody>\n</table>\n<p><em>Breadcrumb (from the home page to the current page):</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">nav</span> <span class=\"hljs-attr\">aria-label</span>=<span class=\"hljs-string\">\"breadcrumb\"</span>&gt;</span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul</span>&gt;</span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li</span>&gt;</span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(site.home) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ site.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">li</span>&gt;</span>\n    </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> section in page.ancestors|<span class=\"hljs-keyword\">reverse</span> %}</span><span class=\"xml\">\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li</span>&gt;</span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(section) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ section.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">li</span>&gt;</span>\n    </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span><span class=\"xml\">\n    </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> page.id != site.home %}</span><span class=\"xml\">\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li</span>&gt;</span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span> <span class=\"hljs-attr\">aria-current</span>=<span class=\"hljs-string\">\"page\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ page.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">li</span>&gt;</span>\n    </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">ul</span>&gt;</span>\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">nav</span>&gt;</span></span></code></pre>\n<aside class=\"note note-tip\"><p>A ready-to-use <a href=\"https://github.com/Cecilapp/Cecil/blob/main/resources/layouts/partials/breadcrumb.html.twig\" target=\"_blank\" rel=\"noopener noreferrer\"><code translate=\"no\">breadcrumb.html.twig</code></a> partial is available:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ <span class=\"hljs-name\">include</span><span class=\"hljs-params\">('partials/breadcrumb.html.twig')</span> }}</span></code></pre></aside>\n<p><em>Sub-sections menu (immediate descendant sections of the current section):</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> page.sections|<span class=\"hljs-keyword\">length</span> %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> section in page.sections|sort_by_title %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li</span>&gt;</span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(section) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ section.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">li</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">ul</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span></code></pre>\n<p><em>Main navigation limited to top level sections (from any page):</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">nav</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> section in site.page(site.home).sections|sort_by_title %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(section) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ section.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">nav</span>&gt;</span></span></code></pre>\n<p><em>Link to the parent section:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> page.<span class=\"hljs-name\">parent</span> %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page.<span class=\"hljs-name\">parent</span>) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span>← </span><span class=\"hljs-template-variable\">{{ page.<span class=\"hljs-name\">parent</span>.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span></code></pre>\n<h3 id=\"page-prev-next\">page.&lt;prev/next&gt;</h3>\n<p>Navigation between pages within the same <em>section</em>, sorted according to the section's <code translate=\"no\">sortby</code> (chronological order for dates).</p>\n<p>With <a href=\"../content/1-pages.md#sub-section\">sub-sections</a>, navigation follows the sections tree: the pages of a top level <em>Section</em> and of all its sub-sections are chained, each sub-section (its index page) being placed among the pages of its parent <em>Section</em> and followed by its own pages.</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n<th>Example</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">page.prev</code></td>\n<td>Previous page.</td>\n<td><em>Page</em></td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.next</code></td>\n<td>Next page.</td>\n<td><em>Page</em></td>\n</tr>\n</tbody>\n</table>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page.prev) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ page.prev.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span></span></code></pre>\n<h3 id=\"page-paginator\">page.paginator</h3>\n<p><em>Paginator</em> helps you build navigation for list pages: homepage, sections, and taxonomies.</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">page.paginator.pages</code></td>\n<td>Pages Collection.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.pages_total</code></td>\n<td>Number total of pages.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.count</code></td>\n<td>Number of paginator's pages.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.current</code></td>\n<td>Position index of the current page.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.links.first</code></td>\n<td>Page ID of the first page.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.links.prev</code></td>\n<td>Page ID of the previous page.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.links.self</code></td>\n<td>Page ID of the current page.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.links.next</code></td>\n<td>Page ID of the next page.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.links.last</code></td>\n<td>Page ID of the last page.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.paginator.links.path</code></td>\n<td>Page ID without the position index.</td>\n</tr>\n</tbody>\n</table>\n<aside class=\"note note-important\"><p>Because links entries are Page ID you must use the <code translate=\"no\">url()</code> function to create working links.<br>\ne.g: <code translate=\"no\">{{ url(page.paginator.links.next) }}</code></p></aside>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> page.paginator %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> page.paginator.links.prev is defined %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page.paginator.links.prev) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span>Previous<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span><span class=\"xml\">\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> page.paginator.links.next is defined %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page.paginator.links.next) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span>Next<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">div</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> page.paginator %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> paginator_index in 1..page.paginator.count %}</span><span class=\"xml\">\n    </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> paginator_index != page.paginator.current %}</span><span class=\"xml\">\n      </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">if</span></span> paginator_index == 1 %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page.paginator.links.first) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ paginator_index }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n      </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">else</span> %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page.paginator.links.path ~ '/' ~ paginator_index) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ paginator_index }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n      </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span><span class=\"xml\">\n    </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">else</span> %}</span><span class=\"xml\">\n  </span><span class=\"hljs-template-variable\">{{ paginator_index }}</span><span class=\"xml\">\n    </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span><span class=\"xml\">\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">div</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endif</span></span> %}</span></code></pre>\n<h3 id=\"taxonomy\">Taxonomy</h3>\n<p>Variables available in <em>vocabulary</em> and <em>term</em> templates.</p>\n<h4>Vocabulary</h4>\n<p>Page <code translate=\"no\">/&lt;plural&gt;/</code> (e.g.: <code translate=\"no\">/categories/</code>).</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">page.plural</code></td>\n<td>Vocabulary name in plural form.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.singular</code></td>\n<td>Vocabulary name in singular form.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.terms</code></td>\n<td>List of terms (<em>Collection</em>).</td>\n</tr>\n</tbody>\n</table>\n<p>Each term of <code translate=\"no\">page.terms</code> provides <code translate=\"no\">term.id</code> (term ID, e.g.: <code translate=\"no\">categories/php</code>), <code translate=\"no\">term.name</code> (term name, e.g.: <code translate=\"no\">PHP</code>) and the number of its pages with <code translate=\"no\">term|length</code>.</p>\n<h4>Term</h4>\n<p>Page <code translate=\"no\">/&lt;plural&gt;/&lt;term&gt;/</code> (e.g.: <code translate=\"no\">/categories/php/</code>).</p>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">page.title</code></td>\n<td>Term name.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.term</code></td>\n<td>Term ID (e.g.: <code translate=\"no\">categories/php</code>).</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.plural</code></td>\n<td>Vocabulary name in plural form.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.singular</code></td>\n<td>Vocabulary name in singular form.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">page.pages</code></td>\n<td>List of pages in this term, sorted by date (<em>Collection</em>).</td>\n</tr>\n</tbody>\n</table>\n<h4>Taxonomy example</h4>\n<p>Configuration:</p>\n<pre><code class=\"language-yaml hljs yaml\" translate=\"no\"><span class=\"hljs-attr\">taxonomies:</span>\n  <span class=\"hljs-attr\">categories:</span> <span class=\"hljs-string\">category</span></code></pre>\n<p>Page front matter:</p>\n<pre><code class=\"language-yaml hljs yaml\" translate=\"no\"><span class=\"hljs-meta\">---</span>\n<span class=\"hljs-attr\">categories:</span> <span class=\"hljs-string\">[\"Data</span> <span class=\"hljs-string\">Sovereignty\"]</span>\n<span class=\"hljs-meta\">---</span></code></pre>\n<p>List of terms (<code translate=\"no\">/categories/</code>), in <code translate=\"no\">layouts/taxonomy/categories.html.twig</code>:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">extends</span></span> 'page.html.twig' %}</span><span class=\"xml\">\n\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">block</span></span> content %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ page.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">h1</span>&gt;</span>\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">ul</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> term in page.terms %}</span><span class=\"xml\">\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">li</span>&gt;</span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(term.id) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ term.name }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span> (</span><span class=\"hljs-template-variable\">{{ term|<span class=\"hljs-keyword\">length</span> }}</span><span class=\"xml\">)<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">li</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">ul</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endblock</span></span> %}</span></code></pre>\n<p>List of pages of a term (<code translate=\"no\">/categories/data-sovereignty/</code>), in <code translate=\"no\">layouts/taxonomy/category.html.twig</code>:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">extends</span></span> 'page.html.twig' %}</span><span class=\"xml\">\n\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">block</span></span> content %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h1</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ page.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">h1</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> p in page.paginator.pages ?? page.pages %}</span><span class=\"xml\">\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">article</span>&gt;</span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">h2</span>&gt;</span><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(p) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ p.title }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">h2</span>&gt;</span>\n    <span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">article</span>&gt;</span>\n  </span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url(page.plural) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span>All </span><span class=\"hljs-template-variable\">{{ page.plural }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endblock</span></span> %}</span></code></pre>\n<p>Links to the terms of the current page, in a page template:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">for</span></span> category in page.categories ?? [] %}</span><span class=\"xml\">\n  <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">a</span> <span class=\"hljs-attr\">href</span>=<span class=\"hljs-string\">\"</span></span></span><span class=\"hljs-template-variable\">{{ url('categories/' ~ category) }}</span><span class=\"xml\"><span class=\"hljs-tag\"><span class=\"hljs-string\">\"</span>&gt;</span></span><span class=\"hljs-template-variable\">{{ category }}</span><span class=\"xml\"><span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">a</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endfor</span></span> %}</span></code></pre>\n<aside class=\"note note-tip\"><p>The <a href=\"reference/1-functions.md#url\"><code translate=\"no\">url()</code></a> function slugifies the given string to find the matching page: <code translate=\"no\">url('categories/Data Sovereignty')</code> returns <code translate=\"no\">/categories/data-sovereignty/</code>.</p>\n<p>You can also use the built-in partial <code translate=\"no\">{{ include('partials/terms-list.html.twig', {vocabulary: 'categories'}) }}</code>.</p></aside>\n<h2 id=\"cecil\">cecil</h2>\n<table>\n<thead>\n<tr>\n<th>Variable</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><code translate=\"no\">cecil.url</code></td>\n<td>URL of the Cecil website.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">cecil.version</code></td>\n<td>Cecil current version.</td>\n</tr>\n<tr>\n<td><code translate=\"no\">cecil.poweredby</code></td>\n<td>Print <code translate=\"no\">Cecil v%s</code>, with <code translate=\"no\">%s</code> is the current version.</td>\n</tr>\n</tbody>\n</table>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/reference/sorts/",
      "url": "https://cecil.app/documentation/templates/reference/sorts/",
      "title": "Sorts",
      "summary": "Sort collections of pages, menus or taxonomies.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Sorts\nSorting collections (of pages, menus or taxonomies).\nsort_by_title\nSorts a collection by title (with natural sort).\n{{ collection|sort_by_title }}\nExample:\n{{ site.pages|sort_by_title }}\nsort_by_date\nSorts a collection by date (most recent first).\n{{ collection|sort_by_date(variable='date', desc_title=false) }}\nExample:\n{# sort by date #}\n{{ site.pages|sort_by_date }}\n{# sort by updated variable instead of date #}\n{{ site.pages|sort_by_date(variable='updated') }}\n{# sort items with the same date by desc title #}\n{{ site.pages|sort_by_date(desc_title=true) }}\n{# reverse sort #}\n{{ site.pages|sort_by_date|reverse }}\nsort_by_weight\nSorts a collection by weight (lighter first).\n{{ collection|sort_by_weight }}\nExample:\n{{ site.menus.main|sort_by_weight }}\nsort\nFor more complex cases, you should use Twig’s native sort.\nExample:\n{% set files = site.static|sort((a, b) =&gt; a.date|date('U') &lt; b.date|date('U')) %}",
      "content_html": "<h1>Sorts</h1>\n<p>Sorting collections (of pages, menus or taxonomies).</p>\n<h2 id=\"sort-by-title\">sort_by_title</h2>\n<p>Sorts a collection by title (with <a href=\"https://en.wikipedia.org/wiki/Natural_sort_order\" target=\"_blank\" rel=\"noopener noreferrer\">natural sort</a>).</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ collection|sort_by_title }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ site.pages|sort_by_title }}</span></code></pre>\n<h2 id=\"sort-by-date\">sort_by_date</h2>\n<p>Sorts a collection by date (most recent first).</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ collection|sort_by_date(variable='<span class=\"hljs-name\">date</span>', desc_title=false) }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# sort by date #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ site.pages|sort_by_date }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# sort by updated variable instead of date #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ site.pages|sort_by_date(variable='updated') }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# sort items with the same date by desc title #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ site.pages|sort_by_date(desc_title=true) }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# reverse sort #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ site.pages|sort_by_date|<span class=\"hljs-keyword\">reverse</span> }}</span></code></pre>\n<h2 id=\"sort-by-weight\">sort_by_weight</h2>\n<p>Sorts a collection by weight (lighter first).</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ collection|sort_by_weight }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ site.menus.main|sort_by_weight }}</span></code></pre>\n<h2 id=\"sort\">sort</h2>\n<p>For more complex cases, you should use <a href=\"https://twig.symfony.com/doc/filters/sort.html\" target=\"_blank\" rel=\"noopener noreferrer\">Twig’s native <code translate=\"no\">sort</code></a>.</p>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> files = site.static|<span class=\"hljs-keyword\">sort</span>((a, b) =&gt; a.<span class=\"hljs-name\">date</span>|<span class=\"hljs-keyword\">date</span>('U') &lt; b.<span class=\"hljs-name\">date</span>|<span class=\"hljs-keyword\">date</span>('U')) %}</span></code></pre>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/reference/filters/",
      "url": "https://cecil.app/documentation/templates/reference/filters/",
      "title": "Filters",
      "summary": "filter_by, markdown_to_html, toc, slugify, excerpt, highlight, preg_*, etc.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Filters\nVariables can be modified by filters. Filters are separated from the variable by a pipe symbol (|). Multiple filters can be chained. The output of one filter is applied to the next.\n{{ page.title|truncate(25)|capitalize }}\nfilter_by\nFilters a pages collection by variable name\/value.\n{{ collection|filter_by(variable, value) }}\nExample:\n{{ pages|filter_by('section', 'blog') }}\nfilter\nFor more complex cases, you should use Twig’s native filter.\nExample:\n{% pages|filter(p =&gt; p.virtual == false and p.id not in ['page-1', 'page-2']) %}\nmarkdown_to_html\nConverts a Markdown string to HTML.\n{{ markdown|markdown_to_html }}\n{% apply markdown_to_html %}\n{# Markdown here #}\n{% endapply %}\nExamples:\n{% set markdown = '**This is bold text**' %}\n{{ markdown|markdown_to_html }}\n{% apply markdown_to_html %}\n**This is bold text**\n{% endapply %}\ntoc\nExtracts only headings matching the given selectors (h2, h3, etc.), or those defined in config pages.body.toc if not specified.\nThe format parameter defines the output format: html or json.\nThe url parameter is used to build links to headings.\n{{ markdown|toc(format, selectors, url) }}\nExamples:\n{{ page.body|toc }}\n{{ page.body|toc('html') }}\n{{ page.body|toc(selectors=['h2']) }}\n{{ page.body|toc(url=url(page)) }}\njson_decode\nConverts a JSON string to an array.\n{{ json|json_decode }}\nExample:\n{% set json = '{\"foo\": \"bar\"}' %}\n{% set array = json|json_decode %}\n{{ array.foo }}\nyaml_parse\nConverts a YAML string to an array.\n{{ yaml|yaml_parse }}\nExample:\n{% set yaml = 'key: value' %}\n{% set array = yaml|yaml_parse %}\n{{ array.key }}\nslugify\nConverts a string to a slug.\n{{ string|slugify }}\nu\nThe u filter wraps a text in a Unicode object (a Symfony UnicodeString instance) that exposes methods to \"manipulate\" the string.\nExample:\n{{ 'cecil_string with twig'|u.camel.title }}\n\nCecilStringWithTwig\n\nsingular\nThe singular filter transforms a given noun in its plural form into its singular version.\n{{ string|singular(locale)}}\nExample:\n{# English (en) rules are used by default #}\n{{ 'partitions'|singular }}\n\npartition\n\n{{ 'partitions'|singular('fr') }}\n\npartition\n\nplural\nThe plural filter transforms a given noun in its singular form into its plural version.\n{{ string|plural(locale)}}\nExample:\n{# English (en) rules are used by default #}\n{{ 'animal'|plural }}\n\nanimals\n\n{{ 'animal'|plural('fr') }}\n\nanimaux\n\nexcerpt\nTruncates a string and appends suffix.\n{{ string|excerpt(length, suffix) }}\n\n\n\nOption\nDescription\nType\nDefault\n\n\n\n\nlength\nTruncates after this number of characters.\ninteger\n450\n\n\nsuffix\nAppends characters.\nstring\n…\n\n\n\nExamples:\n{{ variable|excerpt }}\n{{ variable|excerpt(250, '...') }}\nexcerpt_html\nReads characters before or after &lt;!-- excerpt --&gt; or &lt;!-- break --&gt; tag.\nSee Content documentation for details.\n{{ string|excerpt_html({separator, capture}) }}\n\n\n\nOption\nDescription\nType\nDefault\n\n\n\n\nseparator\nString to use as separator.\nstring\nexcerpt|break\n\n\ncapture\nPart to capture, before or after the separator.\nstring\nbefore\n\n\n\nExamples:\n{{ variable|excerpt_html }}\n{{ variable|excerpt_html({separator: 'excerpt|break', capture: 'before'}) }}\n{{ variable|excerpt_html({capture: 'after'}) }}\nhighlight\nHighlights a code string with highlight.php.\n{{ code|highlight(language) }}\nExamples:\n{{ '&lt;?php echo $highlighted-&gt;value; ?&gt;'|highlight('php') }}\npreg_split\nSplits a string into an array using a regular expression.\n{{ string|preg_split(pattern, limit) }}\nExample:\n{% set headers = page.content|preg_split('\/&lt;br[^&gt;]*&gt;\/') %}\npreg_match_all\nPerforms a regular expression match and return the group for all matches.\n{{ string|preg_match_all(pattern, group) }}\nExample:\n{% set tags = page.content|preg_match_all('\/&lt;[^&gt;]+&gt;(.*)&lt;\\\/[^&gt;]+&gt;\/') %}\nhex_to_rgb\nConverts a hexadecimal color to RGB.\n{{ color|hex_to_rgb }}",
      "content_html": "<h1>Filters</h1>\n<p>Variables can be modified by <a href=\"https://twig.symfony.com/doc/filters/index.html\" target=\"_blank\" rel=\"noopener noreferrer\">filters</a>. Filters are separated from the variable by a pipe symbol (<code translate=\"no\">|</code>). Multiple filters can be chained. The output of one filter is applied to the next.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ page.title|truncate(25)|<span class=\"hljs-keyword\">capitalize</span> }}</span></code></pre>\n<h2 id=\"filter-by\">filter_by</h2>\n<p>Filters a pages collection by variable name/value.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ collection|filter_by(variable, value) }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ pages|filter_by('section', 'blog') }}</span></code></pre>\n<h2 id=\"filter\">filter</h2>\n<p>For more complex cases, you should use <a href=\"https://twig.symfony.com/doc/filters/filter.html\" target=\"_blank\" rel=\"noopener noreferrer\">Twig’s native <code translate=\"no\">filter</code></a>.</p>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">pages</span>|<span class=\"hljs-keyword\">filter</span>(p =&gt; p.virtual == false and p.id not in ['page-1', 'page-2']) %}</span></code></pre>\n<h2 id=\"markdown-to-html\">markdown_to_html</h2>\n<p>Converts a Markdown string to HTML.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ markdown|markdown_to_html }}</span></code></pre>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">apply</span></span> markdown_to_html %}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# Markdown here #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endapply</span></span> %}</span></code></pre>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> markdown = '**This is bold text**' %}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ markdown|markdown_to_html }}</span></code></pre>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">apply</span></span> markdown_to_html %}</span><span class=\"xml\">\n**This is bold text**\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">endapply</span></span> %}</span></code></pre>\n<h2 id=\"toc\">toc</h2>\n<p>Extracts only headings matching the given <code translate=\"no\">selectors</code> (h2, h3, etc.), or those defined in config <code translate=\"no\">pages.body.toc</code> if not specified.<br>\nThe <code translate=\"no\">format</code> parameter defines the output format: <code translate=\"no\">html</code> or <code translate=\"no\">json</code>.<br>\nThe <code translate=\"no\">url</code> parameter is used to build links to headings.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ markdown|toc(format, selectors, url) }}</span></code></pre>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ page.body|toc }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ page.body|toc('html') }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ page.body|toc(selectors=['h2']) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ page.body|toc(url=url(page)) }}</span></code></pre>\n<h2 id=\"json-decode\">json_decode</h2>\n<p>Converts a JSON string to an array.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ json|json_decode }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> json = '{\"foo\": \"bar\"}' %}</span><span class=\"xml\">\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> array = json|json_decode %}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ array.foo }}</span></code></pre>\n<h2 id=\"yaml-parse\">yaml_parse</h2>\n<p>Converts a YAML string to an array.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ yaml|yaml_parse }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> yaml = 'key: value' %}</span><span class=\"xml\">\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> array = yaml|yaml_parse %}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ array.key }}</span></code></pre>\n<h2 id=\"slugify\">slugify</h2>\n<p>Converts a string to a slug.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ string|slugify }}</span></code></pre>\n<h2 id=\"u\">u</h2>\n<p>The <code translate=\"no\">u</code> filter wraps a text in a Unicode object (a <a href=\"https://symfony.com/doc/current/components/string.html\" target=\"_blank\" rel=\"noopener noreferrer\">Symfony UnicodeString instance</a>) that exposes methods to \"manipulate\" the string.</p>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ 'cecil_string with twig'|u.camel.title }}</span></code></pre>\n<blockquote>\n<p>CecilStringWithTwig</p>\n</blockquote>\n<h2 id=\"singular\">singular</h2>\n<p>The <code translate=\"no\">singular</code> filter transforms a given noun in its plural form into its singular version.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ string|singular(locale)}}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# English (en) rules are used by default #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ 'partitions'|singular }}</span></code></pre>\n<blockquote>\n<p>partition</p>\n</blockquote>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ 'partitions'|singular('fr') }}</span></code></pre>\n<blockquote>\n<p>partition</p>\n</blockquote>\n<h2 id=\"plural\">plural</h2>\n<p>The <code translate=\"no\">plural</code> filter transforms a given noun in its singular form into its plural version.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ string|plural(locale)}}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# English (en) rules are used by default #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ 'animal'|plural }}</span></code></pre>\n<blockquote>\n<p>animals</p>\n</blockquote>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ 'animal'|plural('fr') }}</span></code></pre>\n<blockquote>\n<p>animaux</p>\n</blockquote>\n<h2 id=\"excerpt\">excerpt</h2>\n<p>Truncates a string and appends suffix.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ string|excerpt(length, suffix) }}</span></code></pre>\n<table>\n<thead>\n<tr>\n<th>Option</th>\n<th>Description</th>\n<th>Type</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>length</td>\n<td>Truncates after this number of characters.</td>\n<td>integer</td>\n<td>450</td>\n</tr>\n<tr>\n<td>suffix</td>\n<td>Appends characters.</td>\n<td>string</td>\n<td><code translate=\"no\">…</code></td>\n</tr>\n</tbody>\n</table>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ variable|excerpt }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ variable|excerpt(250, '...') }}</span></code></pre>\n<h2 id=\"excerpt-html\">excerpt_html</h2>\n<p>Reads characters before or after <code translate=\"no\">&lt;!-- excerpt --&gt;</code> or <code translate=\"no\">&lt;!-- break --&gt;</code> tag.<br>\nSee <a href=\"../../content/3-markdown.md#excerpt\">Content documentation</a> for details.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ string|excerpt_html({separator, capture}) }}</span></code></pre>\n<table>\n<thead>\n<tr>\n<th>Option</th>\n<th>Description</th>\n<th>Type</th>\n<th>Default</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>separator</td>\n<td>String to use as separator.</td>\n<td>string</td>\n<td><code translate=\"no\">excerpt|break</code></td>\n</tr>\n<tr>\n<td>capture</td>\n<td>Part to capture, <code translate=\"no\">before</code> or <code translate=\"no\">after</code> the separator.</td>\n<td>string</td>\n<td><code translate=\"no\">before</code></td>\n</tr>\n</tbody>\n</table>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ variable|excerpt_html }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ variable|excerpt_html({separator: 'excerpt|break', capture: 'before'}) }}</span><span class=\"xml\">\n</span><span class=\"hljs-template-variable\">{{ variable|excerpt_html({capture: 'after'}) }}</span></code></pre>\n<h2 id=\"highlight\">highlight</h2>\n<p>Highlights a code string with <a href=\"https://github.com/scrivo/highlight.php\" target=\"_blank\" rel=\"noopener noreferrer\">highlight.php</a>.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ code|highlight(language) }}</span></code></pre>\n<p><em>Examples:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ '&lt;?php echo $highlighted-&gt;value; ?&gt;'|highlight('php') }}</span></code></pre>\n<h2 id=\"preg-split\">preg_split</h2>\n<p>Splits a string into an array using a regular expression.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ string|preg_split(pattern, limit) }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> headers = page.content|preg_split('/&lt;br[^&gt;]*&gt;/') %}</span></code></pre>\n<h2 id=\"preg-match-all\">preg_match_all</h2>\n<p>Performs a regular expression match and return the group for all matches.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ string|preg_match_all(pattern, group) }}</span></code></pre>\n<p><em>Example:</em></p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\"><span class=\"hljs-keyword\">set</span></span> tags = page.content|preg_match_all('/&lt;[^&gt;]+&gt;(.*)&lt;\\/[^&gt;]+&gt;/') %}</span></code></pre>\n<h2 id=\"hex-to-rgb\">hex_to_rgb</h2>\n<p>Converts a hexadecimal color to RGB.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ color|hex_to_rgb }}</span></code></pre>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/components/",
      "url": "https://cecil.app/documentation/templates/components/",
      "title": "Components",
      "summary": "Create reusable template components.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Components\nCecil provides a components logic to give you the power making reusable template \"units\".\nThe components feature is provided by the Twig components extension created by Giorgio Pogliani.\nComponents syntax\nComponents are just Twig templates stored in the components\/ subdirectory and can be used anywhere in your templates:\n{# \/components\/button.twig #}\n&lt;button {{ attributes.merge({class: 'rounded px-4'}) }}&gt;\n    {{ slot }}\n&lt;\/button&gt;\n\nThe slot variable is any content you will add between the opening and the close tag.\n\nTo reach a component you need to use the dedicated tag x followed by : and the filename of your component without extension:\n{# \/index.twig #}\n{% x:button with {class: 'text-white'} %}\n    &lt;strong&gt;Click me&lt;\/strong&gt;\n{% endx %}\nIt will render:\n&lt;button class=\"text-white rounded px-4\"&gt;\n    &lt;strong&gt;Click me&lt;\/strong&gt;\n&lt;\/button&gt;",
      "content_html": "<h1>Components</h1>\n<p>Cecil provides a components logic to give you the power making reusable template \"units\".</p>\n<aside class=\"note note-info\"><p>The components feature is provided by the <a href=\"https://github.com/giorgiopogliani/twig-components\" target=\"_blank\" rel=\"noopener noreferrer\"><em>Twig components extension</em></a> created by Giorgio Pogliani.</p></aside>\n<h2 id=\"components-syntax\">Components syntax</h2>\n<p>Components are just Twig templates stored in the <code translate=\"no\">components/</code> subdirectory and can be used anywhere in your templates:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# /components/button.twig #}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button</span> </span></span><span class=\"hljs-template-variable\">{{ attributes.merge({class: 'rounded px-4'}) }}</span><span class=\"xml\"><span class=\"hljs-tag\">&gt;</span>\n    </span><span class=\"hljs-template-variable\">{{ slot }}</span><span class=\"xml\">\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">button</span>&gt;</span></span></code></pre>\n<blockquote>\n<p>The slot variable is any content you will add between the opening and the close tag.</p>\n</blockquote>\n<p>To reach a component you need to use the dedicated tag <code translate=\"no\">x</code> followed by <code translate=\"no\">:</code> and the filename of your component without extension:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-comment\">{# /index.twig #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">x</span>:button with {class: 'text-white'} %}</span><span class=\"xml\">\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">strong</span>&gt;</span>Click me<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">strong</span>&gt;</span>\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endx</span> %}</span></code></pre>\n<p>It will render:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"xml\"><span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button</span> <span class=\"hljs-attr\">class</span>=<span class=\"hljs-string\">\"text-white rounded px-4\"</span>&gt;</span>\n    <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">strong</span>&gt;</span>Click me<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">strong</span>&gt;</span>\n<span class=\"hljs-tag\">&lt;/<span class=\"hljs-name\">button</span>&gt;</span></span></code></pre>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/localization/",
      "url": "https://cecil.app/documentation/templates/localization/",
      "title": "Localization",
      "summary": "Translate texts and localize dates in templates.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Localization\nCecil support text translation and date localization.\nText translation\nUses the trans tag or filter to translate texts in templates.\n{% trans with variables into locale %}{% endtrans %}\n{{ message|trans(variables = []) }}\nExamples\n{% trans %}Hello World!{% endtrans %}\n{{ message|trans }}\nInclude variables:\n{% trans with {'%name%': 'Arnaud'} %}Hello %name%!{% endtrans %}\n{{ message|trans({'%name%': 'Arnaud'}) }}\nForce locale:\n{% trans into 'fr_FR' %}Hello World!{% endtrans %}\nPluralize:\n{% trans with {'%count%': 42}%}{0}I don't have apples|{1}I have one apple|]1,Inf[I have %count% apples{% endtrans %}\nTranslation files\nTranslation files must be named messages.&lt;locale&gt;.&lt;extension&gt; and stored in the translations directory.\nSupported file extensions are defined by each translation format in layouts.translations.formats.\nThe locale code (e.g.: fr_FR) of a language is defined in the languages entries of the configuration.\nExample:\n&lt;mywebsite&gt;\n└─ translations\n   ├─ messages.fr_FR.mo   &lt;- Machine Object format\n   └─ messages.fr_FR.yaml &lt;- Yaml format\nYou can easily extract translations from your templates with the following command:\nphp cecil.phar util:translations:extract --locale=&lt;code&gt; --show\nUse --save instead of (or in addition to) --show to save the translations to a file. The --locale option is required. The default output format is yaml (use --format=po for gettext PO format).\nPoedit is a simple and cross platform translation editor for gettext (PO), and Poedit Pro supports extraction of translation strings from templates out of the box.\nBe careful about the cache when you update translations files.\nCache can be cleared with with the following command:\nphp cecil.phar cache:clear:translations`\nDate localization\nUses the Twig format_date filter to localize a date in templates.\n{{ page.date|format_date('long') }}\n{# September 30, 2022 #}\nSupported values are: short, medium, long, and full.\nIf you want to use the format_date filter with other locales than \"en\", you should install the intl PHP extension.",
      "content_html": "<h1>Localization</h1>\n<p>Cecil support <a href=\"#text-translation\">text translation</a> and <a href=\"#date-localization\">date localization</a>.</p>\n<h2 id=\"text-translation\">Text translation</h2>\n<p>Uses the <code translate=\"no\">trans</code> <em>tag</em> or <em>filter</em> to translate texts in templates.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">trans</span> with variables into locale %}</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endtrans</span> %}</span></code></pre>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ message|trans(variables = []) }}</span></code></pre>\n<h3 id=\"examples\">Examples</h3>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">trans</span> %}</span><span class=\"xml\">Hello World!</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endtrans</span> %}</span></code></pre>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ message|trans }}</span></code></pre>\n<p>Include variables:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">trans</span> with {'%name%': 'Arnaud'} %}</span><span class=\"xml\">Hello %name%!</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endtrans</span> %}</span></code></pre>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ message|trans({'%name%': 'Arnaud'}) }}</span></code></pre>\n<p>Force locale:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">trans</span> into 'fr_FR' %}</span><span class=\"xml\">Hello World!</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endtrans</span> %}</span></code></pre>\n<p>Pluralize:</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">trans</span> with {'%count%': 42}%}</span><span class=\"xml\">{0}I don't have apples|{1}I have one apple|]1,Inf[I have %count% apples</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endtrans</span> %}</span></code></pre>\n<h2 id=\"translation-files\">Translation files</h2>\n<p>Translation files must be named <code translate=\"no\">messages.&lt;locale&gt;.&lt;extension&gt;</code> and stored in the <a href=\"../configuration/7-layouts.md\"><code translate=\"no\">translations</code></a> directory.<br>\nSupported file extensions are defined by each translation format in <a href=\"../configuration/7-layouts.md#layouts-translations\"><code translate=\"no\">layouts.translations.formats</code></a>.</p>\n<p>The locale code (e.g.: <code translate=\"no\">fr_FR</code>) of a language is defined in the <a href=\"../configuration/2-languages.md#languages\"><code translate=\"no\">languages</code></a> entries of the configuration.</p>\n<p><em>Example:</em></p>\n<pre><code class=\"language-plaintext hljs plaintext\" translate=\"no\">&lt;mywebsite&gt;\n└─ translations\n   ├─ messages.fr_FR.mo   &lt;- Machine Object format\n   └─ messages.fr_FR.yaml &lt;- Yaml format</code></pre>\n<aside class=\"note note-info\"><p>You can easily extract translations from your templates with the following command:</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">php cecil.phar util:translations:extract --locale=&lt;code&gt; --show</code></pre>\n<p>Use <code translate=\"no\">--save</code> instead of (or in addition to) <code translate=\"no\">--show</code> to save the translations to a file. The <code translate=\"no\">--locale</code> option is required. The default output format is <code translate=\"no\">yaml</code> (use <code translate=\"no\">--format=po</code> for gettext PO format).</p></aside>\n<aside class=\"note note-tip\"><p><a href=\"https://poedit.net\" target=\"_blank\" rel=\"noopener noreferrer\"><em>Poedit</em></a> is a simple and cross platform translation editor for gettext (PO), and <a href=\"https://poedit.net/pro\" target=\"_blank\" rel=\"noopener noreferrer\"><em>Poedit Pro</em></a> supports extraction of translation strings from templates out of the box.</p></aside>\n<aside class=\"note note-important\"><p>Be careful about the <a href=\"6-cache.md\">cache</a> when you update translations files.</p>\n<p>Cache can be cleared with with the following command:</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">php cecil.phar cache:clear:translations`</code></pre></aside>\n<h2 id=\"date-localization\">Date localization</h2>\n<p>Uses the Twig <a href=\"https://twig.symfony.com/doc/3.x/filters/format_date.html\" target=\"_blank\" rel=\"noopener noreferrer\"><code translate=\"no\">format_date</code></a> filter to localize a date in templates.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-variable\">{{ page.<span class=\"hljs-name\">date</span>|format_date('long') }}</span><span class=\"xml\">\n</span><span class=\"hljs-comment\">{# September 30, 2022 #}</span></code></pre>\n<p>Supported values are: <code translate=\"no\">short</code>, <code translate=\"no\">medium</code>, <code translate=\"no\">long</code>, and <code translate=\"no\">full</code>.</p>\n<aside class=\"note note-important\"><p>If you want to use the <code translate=\"no\">format_date</code> filter <strong>with other locales than \"en\"</strong>, you should <a href=\"https://php.net/intl.setup\" target=\"_blank\" rel=\"noopener noreferrer\">install the intl PHP extension</a>.</p></aside>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/cache/",
      "url": "https://cecil.app/documentation/templates/cache/",
      "title": "Cache",
      "summary": "Templates cache and fragments cache.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Cache\nCecil uses a cache system to speed up the generation process, it can be disabled or cleared.\nThere are three cache types involved in template rendering: templates, assets, and translations.\nClear cache\nYou can clear the cache with the following commands:\nphp cecil.phar cache:clear               # clear all caches\nphp cecil.phar cache:clear:assets        # clear assets cache\nphp cecil.phar cache:clear:templates     # clear templates cache\nphp cecil.phar cache:clear:translations  # clear translations cache\nIn practice you don't need to clear the cache manually, Cecil does it for you when needed (e.g. when files change).\nFragments cache\nCecil provides a way to cache parts of templates rendering to avoid re-rendering the same partial content multiple times.\nTo use fragments cache, you must wrap the content you want to cache with the cache tag.\n{% cache 'unique-key' %}\n  {# cacheable content #}\n{% endcache %}\nYou should use the cache_key function to be sure to have a unique cache key for each content you want to cache.\nFragments cache is persistent, so if the cache key is too generic, you may end up with wrong content displayed.\nTo clear fragments cache only, you can use the following command:\nphp cecil.phar cache:clear:templates --fragments\nDisable cache\nYou can disable cache with the configuration.\nDisabling cache can slow down the generation process, so it's not recommended.\nDuring local development, if you need to clear cache before each generation, you can use the following option:\nphp cecil.phar serve --clear-cache          # clear all caches\nphp cecil.phar serve --clear-cache=&lt;regex&gt;  # clear cache for cache key matches with the regular expression &lt;regex&gt;\nExample:\nphp cecil.phar serve --clear-cache=css  # clear cache for all CSS files",
      "content_html": "<h1>Cache</h1>\n<p>Cecil uses a cache system to speed up the generation process, it can be disabled or cleared.</p>\n<p>There are three cache types involved in template rendering: templates, <a href=\"../assets/index.md#asset\">assets</a>, and <a href=\"5-localization.md#translation-files\">translations</a>.</p>\n<h2 id=\"clear-cache\">Clear cache</h2>\n<p>You can clear the cache with the following commands:</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">php cecil.phar cache:clear               <span class=\"hljs-comment\"># clear all caches</span>\nphp cecil.phar cache:clear:assets        <span class=\"hljs-comment\"># clear assets cache</span>\nphp cecil.phar cache:clear:templates     <span class=\"hljs-comment\"># clear templates cache</span>\nphp cecil.phar cache:clear:translations  <span class=\"hljs-comment\"># clear translations cache</span></code></pre>\n<aside class=\"note note-important\"><p>In practice you don't need to clear the cache manually, Cecil does it for you when needed (e.g. when files change).</p></aside>\n<h2 id=\"fragments-cache\">Fragments cache</h2>\n<p>Cecil provides a way to cache parts of templates rendering to avoid re-rendering the same partial content multiple times.</p>\n<p>To use <em>fragments</em> cache, you must wrap the content you want to cache with the <a href=\"https://twig.symfony.com/doc/tags/cache.html\" target=\"_blank\" rel=\"noopener noreferrer\"><code translate=\"no\">cache</code> tag</a>.</p>\n<pre><code class=\"language-twig hljs twig\" translate=\"no\"><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">cache</span> 'unique-key' %}</span><span class=\"xml\">\n  </span><span class=\"hljs-comment\">{# cacheable content #}</span><span class=\"xml\">\n</span><span class=\"hljs-template-tag\">{% <span class=\"hljs-name\">endcache</span> %}</span></code></pre>\n<aside class=\"note note-tip\"><p>You should use the <a href=\"reference/1-functions.md#cache-key\"><code translate=\"no\">cache_key</code> function</a> to be sure to have a unique cache key for each content you want to cache.</p></aside>\n<aside class=\"note note-warning\"><p><em>Fragments</em> cache is persistent, so if the cache key is too generic, you may end up with wrong content displayed.</p></aside>\n<p>To clear fragments cache only, you can use the following command:</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">php cecil.phar cache:clear:templates --fragments</code></pre>\n<h2 id=\"disable-cache\">Disable cache</h2>\n<p>You can disable cache with the <a href=\"../configuration/9-cache.md\">configuration</a>.</p>\n<aside class=\"note note-warning\"><p>Disabling cache can slow down the generation process, so it's not recommended.</p>\n<p>During local development, if you need to clear cache before each generation, you can use the following option:</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">php cecil.phar serve --clear-cache          <span class=\"hljs-comment\"># clear all caches</span>\nphp cecil.phar serve --clear-cache=&lt;regex&gt;  <span class=\"hljs-comment\"># clear cache for cache key matches with the regular expression &lt;regex&gt;</span></code></pre>\n<p>Example:</p>\n<pre><code class=\"language-bash hljs bash\" translate=\"no\">php cecil.phar serve --clear-cache=css  <span class=\"hljs-comment\"># clear cache for all CSS files</span></code></pre></aside>",
      "language": "en"
    },
    {
      "id": "https://cecil.app/documentation/templates/extend/",
      "url": "https://cecil.app/documentation/templates/extend/",
      "title": "Extend",
      "summary": "Add custom functions and filters, or use a theme.",
      "date_published": "2021-05-07T00:00:00+00:00",
      "date_modified": "2026-10-05T00:00:00+00:00","content_text": "Extend\nFunctions and filters\nYou can add custom functions and custom filters with a Twig extension.\nTheme\nIt’s easy to build a theme, you just have to create a folder &lt;theme&gt; with the following structure (like a website but without pages):\n&lt;mywebsite&gt;\n└─ themes\n   └─ &lt;theme&gt;\n      ├─ config.yml\n      ├─ assets\n      ├─ layouts\n      ├─ static\n      └─ translations",
      "content_html": "<h1>Extend</h1>\n<h2 id=\"functions-and-filters\">Functions and filters</h2>\n<p>You can add custom <a href=\"reference/1-functions.md\">functions</a> and custom <a href=\"reference/3-filters.md\">filters</a> with a <a href=\"../developers/1-extend.md#twig-extension\"><strong><em>Twig extension</em></strong></a>.</p>\n<h2 id=\"theme\">Theme</h2>\n<p>It’s easy to build a theme, you just have to create a folder <code translate=\"no\">&lt;theme&gt;</code> with the following structure (like a website but without pages):</p>\n<pre><code class=\"language-plaintext hljs plaintext\" translate=\"no\">&lt;mywebsite&gt;\n└─ themes\n   └─ &lt;theme&gt;\n      ├─ config.yml\n      ├─ assets\n      ├─ layouts\n      ├─ static\n      └─ translations</code></pre>",
      "language": "en"
    }
  ]
}
