<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://cecil.app/xsl/atom.xsl" media="all"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <id>https://cecil.app/documentation/content/</id>
  <title>Cecil - Content</title>
  <subtitle><![CDATA[Cecil is a command-line PHP application that merges Markdown pages, medias and Twig templates to generate a static website.]]></subtitle>
  <link href="https://cecil.app/documentation/content/atom.xml" rel="self" type="application/atom+xml" />
  <link href="https://cecil.app/documentation/content/" rel="alternate" type="text/html" />
  <updated>2026-10-07T22:48:52+00:00</updated>
  <author>
    <name>Cecil</name>
    <uri>https://cecil.app</uri>
  </author>
  <entry xml:lang="en">
    <id>https://cecil.app/documentation/content/pages/</id>
    <title>Pages and sections</title>
    <published>2021-05-07T00:00:00+00:00</published>
    <updated>2026-10-06T00:00:00+00:00</updated>
    <link href="https://cecil.app/documentation/content/pages/" rel="alternate" type="text/html" />
    <content type="html">
      <![CDATA[<h1>Pages and sections</h1>
<p>A page is a file made up of a <a href="#front-matter"><strong>front matter</strong></a> and a <a href="#body"><strong>body</strong></a>.</p>
<h2 id="front-matter">Front matter</h2>
<p>The <em>front matter</em> is a collection of <a href="/documentation/content/front-matter/">variables</a> (in <em>key/value</em> format) surrounded by <code translate="no">---</code>.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">title:</span> <span class="hljs-string">"The title"</span>
<span class="hljs-attr">date:</span> <span class="hljs-number">2019</span><span class="hljs-number">-02</span><span class="hljs-number">-21</span>
<span class="hljs-attr">tags:</span> <span class="hljs-string">[tag</span> <span class="hljs-number">1</span><span class="hljs-string">,</span> <span class="hljs-string">tag</span> <span class="hljs-number">2</span><span class="hljs-string">]</span>
<span class="hljs-attr">customvar:</span> <span class="hljs-string">"Value of customvar"</span>
<span class="hljs-meta">---</span></code></pre>
<aside class="note note-info"><p>You can also use <code translate="no">&lt;!-- --&gt;</code> or <code translate="no">+++</code> as separator.</p></aside>
<h2 id="body">Body</h2>
<p><em>Body</em> is the main content of a page, it could be written in <a href="/documentation/content/markdown/">Markdown</a> or in plain text.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no"><span class="hljs-section"># Header</span>

[toc]

<span class="hljs-section">## Sub-Header 1</span>

Lorem ipsum dolor [<span class="hljs-string">sit amet</span>](<span class="hljs-link">https://example.com</span>), consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
<span class="xml"><span class="hljs-comment">&lt;!-- excerpt --&gt;</span></span>
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

<span class="hljs-section">## Sub-Header 2</span>

![<span class="hljs-string">Description</span>](<span class="hljs-link">/image.jpg "Title"</span>)

<span class="hljs-section">## Sub-Header 3</span>

:::tip
This is advice.
:::</code></pre>
<h2 id="file-prefix">File prefix</h2>
<p>The filename can contain a prefix to define <code translate="no">date</code> or <code translate="no">weight</code> variables of the page (used by <a href="/documentation/templates/reference/sorts/#sort-by-date"><code translate="no">sortby</code></a>).</p>
<aside class="note note-info"><p>Default prefix separators: <code translate="no">_</code> and <code translate="no">-</code>.</p>
<p>You can customize them with the <a href="/documentation/configuration/pages/#pages-prefix-separator"><code translate="no">pages.prefix.separator</code></a> option.</p></aside>
<h3 id="date">date</h3>
<p>The <em>date prefix</em> is used to set the <code translate="no">date</code> of the page, and must be a valid date format (i.e.: « YYYY-MM-DD »).</p>
<p><em>Example:</em></p>
<p>In « 2019-04-23_My blog post.md »:</p>
<ul>
<li>the prefix is « 2019-04-23 »</li>
<li>the <code translate="no">date</code> of the page is « 2019-04-23 »</li>
<li>the <code translate="no">title</code> of the page is « My blog post »</li>
</ul>
<h3 id="weight">weight</h3>
<p>The <em>weight prefix</em> is used to set the sort order of the page, and must be a valid integer value.</p>
<p><em>Example:</em></p>
<p>In « 1_The first project.md »:</p>
<ul>
<li>the prefix is « 1 »</li>
<li>the <code translate="no">weight</code> of the page is « 1 »</li>
<li>the <code translate="no">title</code> of the page is « The first project »</li>
</ul>
<h2 id="section">Section</h2>
<p>Some dedicated variables can be used in a custom <em>Section</em> (i.e.: <code translate="no">&lt;section&gt;/index.md</code>).</p>
<h3 id="sortby">sortby</h3>
<p>The order of pages in a <em>Section</em> can be changed.</p>
<p>Available values are:</p>
<ul>
<li><code translate="no">date</code>: more recent first</li>
<li><code translate="no">title</code>: alphabetic order</li>
<li><code translate="no">weight</code>: lightest first</li>
</ul>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">sortby:</span> <span class="hljs-string">title</span>
<span class="hljs-meta">---</span></code></pre>
<p><strong>More options:</strong></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">sortby:</span>
  <span class="hljs-attr">variable:</span> <span class="hljs-string">date</span>    <span class="hljs-comment"># "date", "updated", "title" or "weight"</span>
  <span class="hljs-attr">desc_title:</span> <span class="hljs-literal">false</span> <span class="hljs-comment"># used with "date" or "updated" variable value to sort by desc title order if items have the same date</span>
  <span class="hljs-attr">reverse:</span> <span class="hljs-literal">false</span>    <span class="hljs-comment"># reversed if true</span>
<span class="hljs-meta">---</span></code></pre>
<h3 id="pagination">pagination</h3>
<p>The global <a href="/documentation/configuration/pages/#pages-pagination">pagination configuration</a> is used by default, but you can change it for a specific <em>Section</em>.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">pagination:</span>
  <span class="hljs-attr">max:</span> <span class="hljs-number">5</span>
  <span class="hljs-attr">path:</span> <span class="hljs-string">"page"</span>
<span class="hljs-meta">---</span></code></pre>
<p>Pagination can be disabled for a <em>Section</em>:</p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">pagination:</span> <span class="hljs-literal">false</span>
<span class="hljs-meta">---</span></code></pre>
<h3 id="cascade">cascade</h3>
<p>Any variables in <code translate="no">cascade</code> are added to the front matter of all <em>sub pages</em>.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">cascade:</span>
  <span class="hljs-attr">banner:</span> <span class="hljs-string">image.jpg</span>
<span class="hljs-meta">---</span></code></pre>
<aside class="note note-info"><p>Existing variables are not overridden.</p></aside>
<h3 id="circular">circular</h3>
<p>Set <code translate="no">circular</code> to <code translate="no">true</code> to enable circular navigation with <a href="/documentation/templates/variables/#page-prev-next"><em>page.&lt;prev/next&gt;</em></a>.</p>
<aside class="note note-info"><p>With <a href="#sub-section">sub-sections</a>, only the <code translate="no">circular</code> value of the top level <em>Section</em> is used.</p></aside>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">circular:</span> <span class="hljs-literal">true</span>
<span class="hljs-meta">---</span></code></pre>
<h3 id="sub-section">Sub-section</h3>
<p>A nested folder that explicitly contains an <code translate="no">index.md</code> file is turned into a <em>sub-section</em> of its parent <em>Section</em>.</p>
<pre><code class="language-plaintext hljs plaintext" translate="no">&lt;mywebsite&gt;
└─ pages
   └─ blog                 &lt;- Section
      ├─ index.md
      ├─ post-1.md         &lt;- Page in Section "blog"
      └─ 2024              &lt;- Sub-section (contains an "index.md")
         ├─ index.md
         └─ post-2.md      &lt;- Page in Section "blog" *and* sub-section "blog/2024"</code></pre>
<p>A <em>sub-section</em>:</p>
<ul>
<li>is a <em>Section</em> (same type, variables and <a href="/documentation/templates/lookup-rules/#type-section">layout</a> resolution) available at its own URL (e.g.: <code translate="no">/blog/2024/</code>)</li>
<li>is rendered with the layouts of its parent <em>Sections</em> if it doesn't have its own (e.g.: <code translate="no">blog/list.html.twig</code>)</li>
<li>can be nested at any depth (e.g.: <code translate="no">blog/2024/06/</code>)</li>
<li>lists its own pages, and its pages also belong to each of their parent <em>Sections</em></li>
<li>is <strong>not</strong> listed in its parent <em>Section</em></li>
<li>is placed in the <a href="/documentation/templates/variables/#page-prev-next"><em>page.&lt;prev/next&gt;</em></a> navigation of its parent <em>Section</em> (according to its <code translate="no">sortby</code>), followed by its own pages</li>
</ul>
<aside class="note note-info"><p>A nested folder <strong>without</strong> an <code translate="no">index.md</code> file is not a <em>sub-section</em>: its pages simply belong to the parent <em>Section</em>.</p></aside>
<h2 id="home-page">Home page</h2>
<p>Like another section, <em>Home page</em> support <code translate="no">sortby</code> and <code translate="no">pagination</code> configuration.</p>
<h3 id="pagesfrom">pagesfrom</h3>
<p>Set a valid <em>Section</em> name in <code translate="no">pagesfrom</code> to use pages collection from this <em>Section</em> in <em>Home page</em>.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">pagesfrom:</span> <span class="hljs-string">blog</span>
<span class="hljs-meta">---</span></code></pre>]]>
    </content>
  </entry>
  <entry xml:lang="en">
    <id>https://cecil.app/documentation/content/front-matter/</id>
    <title>Front matter</title>
    <published>2021-05-07T00:00:00+00:00</published>
    <updated>2026-10-03T00:00:00+00:00</updated>
    <link href="https://cecil.app/documentation/content/front-matter/" rel="alternate" type="text/html" />
    <content type="html">
      <![CDATA[<h1>Front matter</h1>
<p>The <em>front matter</em> can contains custom variables applied to the current page.</p>
<p>It must be the first thing in the file and must be a valid <a href="https://en.wikipedia.org/wiki/YAML" target="_blank" rel="noopener noreferrer">YAML</a>.</p>
<h2 id="predefined-variables">Predefined variables</h2>
<table>
<thead>
<tr>
<th>Variable</th>
<th>Description</th>
<th>Default value</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><code translate="no">title</code></td>
<td>Title</td>
<td>File name without extension.</td>
<td><code translate="no">Post 1</code></td>
</tr>
<tr>
<td><code translate="no">layout</code></td>
<td>Template</td>
<td>See <a href="/documentation/templates/lookup-rules/#lookup-rules"><em>Lookup rules</em></a>.</td>
<td><code translate="no">404</code></td>
</tr>
<tr>
<td><code translate="no">date</code></td>
<td>Creation date</td>
<td>File creation date (PHP <em>DateTime</em> object).</td>
<td><code translate="no">2019/04/15</code></td>
</tr>
<tr>
<td><code translate="no">section</code></td>
<td>Section</td>
<td>Page's <em>Section</em>.</td>
<td><code translate="no">blog</code></td>
</tr>
<tr>
<td><code translate="no">path</code></td>
<td>Path</td>
<td>Page's <em>path</em>.</td>
<td><code translate="no">blog/post-1</code></td>
</tr>
<tr>
<td><code translate="no">slug</code></td>
<td>Slug</td>
<td>Page's <em>slug</em>.</td>
<td><code translate="no">post-1</code></td>
</tr>
<tr>
<td><code translate="no">published</code></td>
<td>Published or not</td>
<td><code translate="no">true</code>.</td>
<td><code translate="no">false</code></td>
</tr>
<tr>
<td><code translate="no">draft</code></td>
<td>Published or not</td>
<td><code translate="no">false</code>.</td>
<td><code translate="no">true</code></td>
</tr>
</tbody>
</table>
<aside class="note note-info"><p>All the predefined variables can be overridden except <code translate="no">section</code>.</p></aside>
<h2 id="updated">updated</h2>
<p>The <code translate="no">updated</code> variable is used to define the last modification date of a page.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">updated:</span> <span class="hljs-number">2026</span><span class="hljs-number">-02</span><span class="hljs-number">-02</span>
<span class="hljs-meta">---</span></code></pre>
<aside class="note note-warning"><p>Before version 8.80.1, the <code translate="no">updated</code> variable was a predefined variable. It is now an optional variable (and must be defined in the front matter to be used).</p></aside>
<h2 id="menu">menu</h2>
<p>A page can be added to a <a href="/documentation/configuration/site/#menus">menu</a>.</p>
<p>The entry name is the page <code translate="no">title</code> and the URL is the page <code translate="no">path</code>.</p>
<p>The same page can be added to multiple menus, and each entry's position can be set with the <code translate="no">weight</code> key (lowest first). The <code translate="no">name</code> key can be used to override the default entry name per menu.</p>
<p><em>Examples:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">menu:</span> <span class="hljs-string">main</span>
<span class="hljs-meta">---</span></code></pre>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">menu:</span> <span class="hljs-string">[main,</span> <span class="hljs-string">navigation]</span> <span class="hljs-comment"># same page in multiple menus</span>
<span class="hljs-meta">---</span></code></pre>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">menu:</span>
  <span class="hljs-attr">main:</span>
    <span class="hljs-attr">weight:</span> <span class="hljs-number">10</span>
  <span class="hljs-attr">navigation:</span>
    <span class="hljs-attr">weight:</span> <span class="hljs-number">20</span>
<span class="hljs-meta">---</span></code></pre>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">title:</span> <span class="hljs-string">'Our Expertise'</span>
<span class="hljs-attr">menu:</span>
  <span class="hljs-attr">main:</span>
    <span class="hljs-attr">weight:</span> <span class="hljs-number">15</span>
  <span class="hljs-attr">footer:</span>
    <span class="hljs-attr">weight:</span> <span class="hljs-number">15</span>
    <span class="hljs-attr">name:</span> <span class="hljs-string">"Expertise"</span> <span class="hljs-comment"># override the entry name in this menu</span>
<span class="hljs-meta">---</span></code></pre>
<h2 id="taxonomy">Taxonomy</h2>
<p>Taxonomy allows you to connect, relate and classify your website’s content.<br>
In Cecil, these terms are gathered within vocabularies.</p>
<p>Vocabularies are declared in the <a href="/documentation/configuration/site/#taxonomies"><em>Configuration</em></a>.</p>
<dl>
<dt>Vocabulary</dt>
<dd>A categorization of content (e.g.: <code translate="no">tags</code>, <code translate="no">categories</code>, etc.).</dd>
<dt>Term</dt>
<dd>A term is an item of a vocabulary (e.g.: <code translate="no">Development</code>, <code translate="no">PHP</code>, etc.).</dd>
</dl>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">tags:</span> <span class="hljs-string">["Development",</span> <span class="hljs-string">"PHP"</span><span class="hljs-string">]</span>
<span class="hljs-meta">---</span></code></pre>
<p>Cecil then generates, for each vocabulary:</p>
<ul>
<li>a page listing its terms, e.g.: <code translate="no">/tags/</code></li>
<li>a page per term listing its pages, e.g.: <code translate="no">/tags/development/</code> and <code translate="no">/tags/php/</code></li>
</ul>
<p>See <a href="/documentation/templates/lookup-rules/#type-vocabulary">templates lookup rules</a> and <a href="/documentation/templates/variables/#taxonomy">taxonomy variables</a> to customize those pages.</p>
<h2 id="schedule">Schedule</h2>
<p>Schedules pages’ publication.</p>
<p><em>Example:</em></p>
<p>The page will be published if current date is &gt;= 2023-02-07:</p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-attr">schedule:</span>
  <span class="hljs-attr">publish:</span> <span class="hljs-number">2023</span><span class="hljs-number">-02</span><span class="hljs-number">-07</span></code></pre>
<p>This page is published if current date is &lt;= 2022-04-28:</p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-attr">schedule:</span>
  <span class="hljs-attr">expiry:</span> <span class="hljs-number">2022</span><span class="hljs-number">-04</span><span class="hljs-number">-28</span></code></pre>
<h2 id="redirect">redirect</h2>
<p>As indicated by its name, the <code translate="no">redirect</code> variable is used to redirect a page to a dedicated URL.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">redirect:</span> <span class="hljs-string">"https://arnaudligny.fr"</span>
<span class="hljs-meta">---</span></code></pre>
<aside class="note note-info"><p>Redirect works with the <a href="https://github.com/Cecilapp/Cecil/blob/main/resources/layouts/_default/redirect.html.twig" target="_blank" rel="noopener noreferrer"><code translate="no">redirect.html.twig</code></a> template.</p></aside>
<h2 id="alias">alias</h2>
<p>Alias is a redirection to the current page</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">title:</span> <span class="hljs-string">"About"</span>
<span class="hljs-attr">alias:</span>
  <span class="hljs-bullet">-</span> <span class="hljs-string">contact</span>
<span class="hljs-meta">---</span></code></pre>
<p>In the previous example <code translate="no">contact/</code> redirects to <code translate="no">about/</code>.</p>
<h2 id="output">output</h2>
<p>Defines the output format of the page.</p>
<p>Available formats are: <code translate="no">html</code>, <code translate="no">atom</code>, <code translate="no">rss</code>, <code translate="no">json</code>, <code translate="no">xml</code>, etc.<br>
You can define one or more formats in an array.</p>
<p>I’s not required to define an output format, but if you do, it must be one of the available formats defined in the <a href="/documentation/configuration/output/#output-formats"><em>Configuration</em></a>.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">output:</span> <span class="hljs-string">[html,</span> <span class="hljs-string">atom]</span>
<span class="hljs-meta">---</span></code></pre>
<h2 id="external">external</h2>
<p>A page with an <code translate="no">external</code> variable try to fetch the content of the pointed resource.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">external:</span> <span class="hljs-string">"https://raw.githubusercontent.com/Cecilapp/Cecil/main/README.md"</span>
<span class="hljs-meta">---</span></code></pre>
<h2 id="excluded">excluded</h2>
<p>Set <code translate="no">excluded</code> to <code translate="no">true</code> to hide a page from list pages (i.e.: <em>Home page</em>, <em>Section</em>, <em>Sitemap</em>, etc.).</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">excluded:</span> <span class="hljs-literal">true</span>
<span class="hljs-meta">---</span></code></pre>
<aside class="note note-info"><p><code translate="no">excluded</code> is different from <a href="#predefined-variables"><code translate="no">published</code></a>: an excluded page is published but hidden from list pages.</p></aside>
<aside class="note note-warning"><p>Since version 8.49.0, the previous <code translate="no">exclude</code> variable have been changed to <code translate="no">excluded</code>.</p></aside>]]>
    </content>
  </entry>
  <entry xml:lang="en">
    <id>https://cecil.app/documentation/content/markdown/</id>
    <title>Markdown</title>
    <published>2021-05-07T00:00:00+00:00</published>
    <updated>2026-10-03T00:00:00+00:00</updated>
    <link href="https://cecil.app/documentation/content/markdown/" rel="alternate" type="text/html" />
    <content type="html">
      <![CDATA[<h1>Markdown</h1>
<p>Cecil supports <a href="http://daringfireball.net/projects/markdown/syntax" target="_blank" rel="noopener noreferrer">Markdown</a> format, but also <a href="https://michelf.ca/projects/php-markdown/extra/" target="_blank" rel="noopener noreferrer">Markdown Extra</a>.</p>
<p>Cecil also provides <strong>extra features</strong> to enhance your content, see below.</p>
<h2 id="attributes">Attributes</h2>
<p>With <a href="https://michelf.ca/projects/php-markdown/extra/" target="_blank" rel="noopener noreferrer">Markdown Extra</a> you can set an id, class and custom attributes on certain elements using an attribute block.<br>
For instance, put the desired attribute(s) after a header, a fenced code block, a link or an image at the end of the line inside curly brackets, like this:</p>
<pre><code class="language-markdown hljs markdown" translate="no"><span class="hljs-section">## Header {#id .class attribute=value}</span></code></pre>
<aside class="note note-warning"><p>For an inline element, like a link, you must use a line break after the closing brace:</p>
<pre><code class="language-markdown hljs markdown" translate="no">Lorem ipsum [<span class="hljs-string">dolor</span>](<span class="hljs-link">url</span>){attribute=value} 
sit amet.</code></pre></aside>
<h2 id="links">Links</h2>
<p>You can create a link with the syntax <code translate="no">[Text](url)</code>, where <code translate="no">url</code> can be a path, a relative path to a Markdown file, an external URL, etc.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">[<span class="hljs-string">Link to a path</span>](<span class="hljs-link">/about/</span>)
[<span class="hljs-string">Link to a Markdown file</span>](<span class="hljs-link">/about/</span>)
[<span class="hljs-string">Link to Cecil website</span>](<span class="hljs-link">https://cecil.app</span>)</code></pre>
<aside class="note note-info"><p>A relative link to a Markdown file is resolved from the folder of the current file (as on GitHub), then replaced by the URL of the targeted page.</p></aside>
<h3 id="link-to-a-page">Link to a page</h3>
<p>You can easily create a link to a page with the syntax <code translate="no">[Page title](page:page-id)</code>.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">[<span class="hljs-string">Link to a blog post</span>](<span class="hljs-link">page:blog/post-1</span>)</code></pre>
<h3 id="external">External</h3>
<p>By default external links have the following value for <code translate="no">rel</code> attribute: <code translate="no">noopener noreferrer</code>.</p>
<p><em>Example:</em></p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">a</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"&lt;url&gt;"</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"noopener noreferrer"</span>&gt;</span>Link to another website<span class="hljs-tag">&lt;/<span class="hljs-name">a</span>&gt;</span></code></pre>
<p>You can change this behavior with <a href="/documentation/configuration/pages/#pages-body-links"><code translate="no">pages.body.links.external</code> options</a>.</p>
<h3 id="embedded-links">Embedded links</h3>
<p>Cecil can try to turn a link into embedded content by using the <code translate="no">{embed}</code> attribute or by setting the global configuration option <code translate="no">pages.body.links.embed.enabled</code> to <code translate="no">true</code>.</p>
<aside class="note note-important"><p>Only <strong>YouTube</strong>, <strong>Vimeo</strong>, <strong>Dailymotion</strong>, and <strong>GitHub Gists</strong> links are supported.</p></aside>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">[<span class="hljs-string">CECIL : LE générateur de SITES STATIQUES en PHP</span>](<span class="hljs-link">https://www.youtube.com/watch?v=ur8koU0iYvc</span>){embed}</code></pre>
<p><div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;">
<iframe src="https://www.youtube-nocookie.com/embed/ur8koU0iYvc" loading="lazy" width="640" height="360" frameborder="0" allow="accelerometer;autoplay;encrypted-media;gyroscope;picture-in-picture;fullscreen;web-share;" allowfullscreen="" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;background-color:#d8d8d8;"></iframe>
</div></p>
<h4>Local video/audio files</h4>
<p>Cecil can also create a video and audio HTML elements, through the file extension.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">[<span class="hljs-string">Video file</span>](<span class="hljs-link">video.mp4</span>){embed controls poster=/images/video-test.png}
[<span class="hljs-string">Audio file</span>](<span class="hljs-link">song.mp3</span>){embed controls}</code></pre>
<p>Is converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">video</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/video.mp4"</span> <span class="hljs-attr">controls</span> <span class="hljs-attr">poster</span>=<span class="hljs-string">"/images/video-test.png"</span> <span class="hljs-attr">style</span>=<span class="hljs-string">"max-width:100%;height:auto;"</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">video</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">audio</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/song.mp3"</span> <span class="hljs-attr">controls</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">audio</span>&gt;</span></code></pre>
<h2 id="images">Images</h2>
<p>To add an image, use an exclamation mark (<code translate="no">!</code>) followed by alternative description in brackets (<code translate="no">[]</code>), and the path or URL to the image in parentheses (<code translate="no">()</code>).<br>
You can optionally add a title in quotation marks.</p>
<pre><code class="language-markdown hljs markdown" translate="no">![<span class="hljs-string">Alternative description</span>](<span class="hljs-link">/image.jpg "Image title"</span>)</code></pre>
<aside class="note note-info"><p>The path should be relative to the root of your website (e.g.: <code translate="no">/image.jpg</code>), however Cecil is able to normalize a path relative to <em>assets</em> and <em>static</em> directories (e.g.: <code translate="no">../../assets/image.jpg</code>).</p></aside>
<h3 id="lazy-loading">Lazy loading</h3>
<p>Cecil adds the attribute <code translate="no">loading="lazy"</code> to each image.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/image.jpg)</code></pre>
<p>Is converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/image.jpg"</span> <span class="hljs-attr">loading</span>=<span class="hljs-string">"lazy"</span>&gt;</span></code></pre>
<aside class="note note-info"><p>You can disable this behavior with the attribute <code translate="no">{loading=eager}</code> or with the <a href="/documentation/configuration/pages/#pages-body-images"><code translate="no">lazy</code> option</a>.</p></aside>
<h3 id="decoding">Decoding</h3>
<p>Cecil adds the attribute <code translate="no">decoding="async"</code> to each image.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/image.jpg)</code></pre>
<p>Is converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/image.jpg"</span> <span class="hljs-attr">decoding</span>=<span class="hljs-string">"async"</span>&gt;</span></code></pre>
<aside class="note note-info"><p>You can disable this behavior with the attribute <code translate="no">{decoding=auto}</code> or with the <a href="/documentation/configuration/pages/#pages-body-images"><code translate="no">decoding</code> option</a>.</p></aside>
<h3 id="resize">Resize</h3>
<p>Each image in the <em>body</em> can be resized automatically by setting a smaller width than the original one, with the extra attribute <code translate="no">{width=X}</code>.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/image.jpg){width=800}</code></pre>
<p>Is converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/thumbnails/800/image.jpg"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"800"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"600"</span>&gt;</span></code></pre>
<aside class="note note-info"><p>Ratio is preserved (<code translate="no">height</code> attribute is calculated automatically), the original file is not altered and the resized version is stored in <code translate="no">/thumbnails/&lt;width&gt;/</code>.</p></aside>
<aside class="note note-important"><p>This feature requires an image processing library: <a href="https://www.php.net/manual/book.imagick.php" target="_blank" rel="noopener noreferrer">Imagick</a> is used first if available (and able to read JPEG and PNG), then <a href="https://www.libvips.org/" target="_blank" rel="noopener noreferrer">libvips</a> (through the PHP <a href="https://www.php.net/manual/book.ffi.php" target="_blank" rel="noopener noreferrer">FFI</a> extension), and finally <a href="https://www.php.net/manual/book.image.php" target="_blank" rel="noopener noreferrer">GD</a> as fallback; otherwise it only adds a <code translate="no">width</code> HTML attribute to the <code translate="no">img</code> tag.</p></aside>
<aside class="note note-info"><p>libvips support is optional and is not bundled with <code translate="no">cecil.phar</code>. To use it, Cecil must be installed with <a href="https://getcomposer.org" target="_blank" rel="noopener noreferrer">Composer</a>, and you need:</p>
<ol>
<li><a href="https://www.libvips.org/install.html" target="_blank" rel="noopener noreferrer">libvips</a> installed on your system</li>
<li>the PHP <a href="https://www.php.net/manual/book.ffi.php" target="_blank" rel="noopener noreferrer">FFI</a> extension enabled</li>
<li>the <code translate="no">intervention/image-driver-vips</code> package installed alongside Cecil</li>
</ol>
<p>If Cecil is a dependency of your project (see <a href="/documentation/developers/library/#libvips-support">Library</a>):</p>
<pre><code class="language-bash hljs bash" translate="no">composer require intervention/image-driver-vips</code></pre>
<p>If Cecil is installed globally:</p>
<pre><code class="language-bash hljs bash" translate="no">composer global require cecil/cecil intervention/image-driver-vips</code></pre></aside>
<h3 id="formats">Formats</h3>
<p>If the <a href="/documentation/configuration/pages/#pages-body-images"><code translate="no">formats</code> option</a> is defined, alternatives images are created and added.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/image.jpg)</code></pre>
<p>Could be converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">picture</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"/image.avif"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"image/avif"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">source</span> <span class="hljs-attr">srcset</span>=<span class="hljs-string">"/image.webp"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"image/webp"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/image.jpg"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">picture</span>&gt;</span></code></pre>
<aside class="note note-important"><p>Please note that <strong>not all image formats</strong> are always included in the PHP image extensions.</p></aside>
<h3 id="responsive">Responsive</h3>
<p>If the <a href="/documentation/configuration/pages/#pages-body-images"><code translate="no">responsive</code> option</a> is enabled, then all images in the <em>body</em> will be made responsive automatically.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/image.jpg){width=800}</code></pre>
<p>will be converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/thumbnails/800/image.jpg"</span> <span class="hljs-attr">width</span>=<span class="hljs-string">"800"</span> <span class="hljs-attr">height</span>=<span class="hljs-string">"600"</span>
  <span class="hljs-attr">srcset</span>=<span class="hljs-string">"/thumbnails/320/image.jpg 320w,
          /thumbnails/640/image.jpg 640w,
          /thumbnails/800/image.jpg 800w"</span>
  <span class="hljs-attr">sizes</span>=<span class="hljs-string">"100vw"</span>
&gt;</span></code></pre>
<aside class="note note-info"><p>Because a body image is converted into an <a href="/documentation/assets/#asset">Asset</a>, the different widths must be defined in <a href="/documentation/configuration/assets/">assets configuration</a>.</p></aside>
<p>The <code translate="no">sizes</code> attribute takes the value of the <code translate="no">assets.images.responsive.sizes.default</code> configuration option, but it can be changed by creating a new entry named after a <em>class</em> added to the image.</p>
<p><em>Example:</em></p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-attr">assets:</span>
  <span class="hljs-attr">images:</span>
    <span class="hljs-attr">responsive:</span>
      <span class="hljs-attr">sizes:</span>
        <span class="hljs-attr">default:</span> <span class="hljs-string">100vw</span>
        <span class="hljs-attr">my_class:</span> <span class="hljs-string">"(max-width: 800px) 768px, 1024px"</span></code></pre>
<pre><code class="language-markdown hljs markdown" translate="no">![](/image.jpg){.my_class}</code></pre>
<aside class="note note-info"><p>You can combine <code translate="no">formats</code> and <code translate="no">responsive</code> options.</p></aside>
<h3 id="css-class">CSS class</h3>
<p>You can set a default value to the <code translate="no">class</code> attribute of each image with the <a href="/documentation/configuration/pages/#pages-body-images"><code translate="no">class</code> option</a>.</p>
<h3 id="caption">Caption</h3>
<p>The optional title can be used to create a caption (<code translate="no">figcaption</code>) automatically by enabling the <a href="/documentation/configuration/pages/#pages-body-images"><code translate="no">caption</code> option</a>.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/images/img.jpg "Title")</code></pre>
<p>Is converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">figure</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">img</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/image.jpg"</span> <span class="hljs-attr">title</span>=<span class="hljs-string">"Title"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">figcaption</span>&gt;</span>Title<span class="hljs-tag">&lt;/<span class="hljs-name">figcaption</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">figure</span>&gt;</span></code></pre>
<aside class="note note-info"><p>Caption supports Markdown content.</p></aside>
<h3 id="localized-image">Localized image</h3>
<p>For translated pages, Cecil first looks for a language-suffixed file when resolving Markdown image paths.</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/images/cecil-logo.png)</code></pre>
<p>With a French page (<code translate="no">fr</code>), Cecil tries <code translate="no">/images/cecil-logo.fr.png</code> first, then falls back to <code translate="no">/images/cecil-logo.png</code>.</p>
<h3 id="placeholder">Placeholder</h3>
<p>As images are typically heavier and slower resources, and they don’t block rendering, we should attempt to give users something to look at while they wait for the image to arrive.</p>
<p>The <code translate="no">placeholder</code> attribute accepts two options:</p>
<ol>
<li><code translate="no">color</code>: display a colored background (based on image dominant color)</li>
<li><code translate="no">lqip</code>: <a href="https://www.guypo.com/introducing-lqip-low-quality-image-placeholders" target="_blank" rel="noopener noreferrer">Low-Quality Image Placeholder</a></li>
</ol>
<p><em>Examples:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">![](/images/img.jpg){placeholder=color}
![](/images/img.jpg){placeholder=lqip}</code></pre>
<aside class="note note-tip"><p>You can set a value to the <code translate="no">placeholder</code> attribute for each image with the <a href="/documentation/configuration/pages/#pages-body-images"><code translate="no">placeholder</code> option</a>.</p></aside>
<aside class="note note-warning"><p>The <code translate="no">lqip</code> option is not compatible with animated GIF.</p></aside>
<h2 id="table-of-contents">Table of contents</h2>
<p>You can add a table of contents with the following Markdown syntax:</p>
<pre><code class="language-markdown hljs markdown" translate="no">[toc]</code></pre>
<aside class="note note-info"><p>By default, the ToC extracts H2 and H3 headings. You can change this behavior with <a href="/documentation/configuration/pages/#pages-body">body options</a>.</p></aside>
<h2 id="excerpt">Excerpt</h2>
<p>An excerpt can be defined in the <em>body</em> with one of those following tags: <code translate="no">excerpt</code> or <code translate="no">break</code>.</p>
<p><em>Example:</em></p>
<pre><code class="language-html hljs xml" translate="no">Introduction.
<span class="hljs-comment">&lt;!-- excerpt --&gt;</span>
Main content.</code></pre>
<p>Then use the <a href="/documentation/templates/reference/filters/#excerpt-html"><code translate="no">excerpt_html</code> filter</a> in your template.</p>
<h2 id="notes">Notes</h2>
<p>Create a <em>Note</em> block (info, tips, important, etc.).</p>
<p><em>Example:</em></p>
<pre><code class="language-markdown hljs markdown" translate="no">:::tip
<span class="hljs-strong">**Tip:**</span> This is advice.
:::</code></pre>
<p>Is converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">aside</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"note note-tip"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">strong</span>&gt;</span>Tip:<span class="hljs-tag">&lt;/<span class="hljs-name">strong</span>&gt;</span> This is advice.
  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">aside</span>&gt;</span></code></pre>
<aside class="note note-tip"><p><strong>Tip:</strong> This is advice.</p></aside>
<p><em>Others examples:</em></p>
<aside class="note"><p>empty</p></aside>
<aside class="note note-info"><p>info</p></aside>
<aside class="note note-tip"><p>tip</p></aside>
<aside class="note note-important"><p>important</p></aside>
<aside class="note note-warning"><p>warning</p></aside>
<aside class="note note-caution"><p>caution</p></aside>
<h2 id="syntax-highlight">Syntax highlight</h2>
<p>Code block syntax highlighting is enabled by default with the <a href="/documentation/configuration/pages/#pages-body-highlight">pages.body.highlight</a> option.</p>
<p>If needed, you can disable it with:</p>
<pre><code class="language-yaml hljs yaml" translate="no"><span class="hljs-attr">pages:</span>
  <span class="hljs-attr">body:</span>
    <span class="hljs-attr">highlight:</span> <span class="hljs-literal">false</span></code></pre>
<p><em>Example:</em></p>
<pre>
```php
echo "Hello world";
```
</pre>
<p>Is rendered to:</p>
<pre><code class="language-php hljs php" translate="no"><span class="hljs-keyword">echo</span> <span class="hljs-string">"Hello world"</span>;</code></pre>
<aside class="note note-info"><p>You can customize the syntax highlighting style by creating your own theme. See the <a href="https://highlightjs.readthedocs.io/en/latest/theme-guide.html" target="_blank" rel="noopener noreferrer">Highlight.js Theme Guide</a>.</p></aside>
<h2 id="inserted-text">Inserted text</h2>
<p>Represents a range of text that has been added.</p>
<pre><code class="language-markdown hljs markdown" translate="no">++text++</code></pre>
<p>Is converted to:</p>
<pre><code class="language-html hljs xml" translate="no"><span class="hljs-tag">&lt;<span class="hljs-name">ins</span>&gt;</span>text<span class="hljs-tag">&lt;/<span class="hljs-name">ins</span>&gt;</span></code></pre>]]>
    </content>
  </entry>
  <entry xml:lang="en">
    <id>https://cecil.app/documentation/content/multilingual/</id>
    <title>Multilingual</title>
    <published>2021-05-07T00:00:00+00:00</published>
    <updated>2026-10-03T00:00:00+00:00</updated>
    <link href="https://cecil.app/documentation/content/multilingual/" rel="alternate" type="text/html" />
    <content type="html">
      <![CDATA[<h1>Multilingual</h1>
<p>If your pages are available in multiple <a href="/documentation/configuration/languages/#languages">languages</a> there is 2 different ways to define it:</p>
<h2 id="through-file-name">Through file name</h2>
<p>This is the common way to translate a page from the main <a href="/documentation/configuration/languages/#language">language</a> to another language.</p>
<p>You just need to duplicate the reference page and suffix it with the target language <code translate="no">code</code> (e.g.: <code translate="no">fr</code>).</p>
<p><em>Example:</em></p>
<pre><code class="language-plaintext hljs plaintext" translate="no">├─ about.md    # the reference page
└─ about.fr.md # the french version (`fr`)</code></pre>
<aside class="note note-tip"><p>You can change the URL of the translated page with the <code translate="no">slug</code> variable in the front matter. For example:</p>
<pre><code class="language-yml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">slug:</span> <span class="hljs-string">a-propos</span>
<span class="hljs-meta">---</span>
<span class="hljs-comment"># about.md    -&gt; /about/</span>
<span class="hljs-comment"># about.fr.md -&gt; /fr/a-propos/</span></code></pre></aside>
<h2 id="through-front-matter">Through front matter</h2>
<p>If you want to create a page in a language other than the main language, without it being a translation of an existing page, you can use the <code translate="no">language</code> variable in its front matter.</p>
<p><em>Example:</em></p>
<pre><code class="language-yml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">language:</span> <span class="hljs-string">fr</span>
<span class="hljs-meta">---</span></code></pre>
<h2 id="link-translated-pages">Link translated pages</h2>
<p>Each translated page reference the pages in others languages.</p>
<p>Those pages collection is available in <a href="/documentation/templates/variables/#page">templates</a> with the following variable:</p>
<pre><code class="language-twig hljs twig" translate="no"><span class="hljs-template-variable">{{ page.translations }}</span></code></pre>
<aside class="note note-info"><p>The <code translate="no">langref</code> variable is provided by default, but you can change it in the front matter:</p>
<pre><code class="language-yml hljs yaml" translate="no"><span class="hljs-meta">---</span>
<span class="hljs-attr">langref:</span> <span class="hljs-string">my-page-ref</span>
<span class="hljs-meta">---</span></code></pre></aside>]]>
    </content>
  </entry>
  <entry xml:lang="en">
    <id>https://cecil.app/documentation/content/dynamic-content/</id>
    <title>Dynamic content</title>
    <published>2021-05-07T00:00:00+00:00</published>
    <updated>2026-10-03T00:00:00+00:00</updated>
    <link href="https://cecil.app/documentation/content/dynamic-content/" rel="alternate" type="text/html" />
    <content type="html">
      <![CDATA[<h1>Dynamic content</h1>
<p>You can create dynamic content in a page by using the <a href="https://twig.symfony.com/doc/3.x/functions/template_from_string.html" target="_blank" rel="noopener noreferrer"><code translate="no">template_from_string</code></a> Twig function.</p>
<pre><code class="language-twig hljs twig" translate="no"><span class="hljs-template-variable">{{ <span class="hljs-name">include</span><span class="hljs-params">(template_from_string(page.content, "dynamic content for page " ~ page.id)</span>) }}</span></code></pre>
<p>With this, you can use any page variable in the <em>body</em> of the page.</p>
<pre><code class="language-twig hljs twig" translate="no"><span class="xml">--
var: 'value'
---
The value of `var` is </span><span class="hljs-template-variable">{{ page.var }}</span><span class="xml">.</span></code></pre>]]>
    </content>
  </entry>
</feed>
