Cecil logo
What's on this page

Content

There is different kinds of content in Cecil:

Pages
Pages are the main content of the site, written in Markdown.
Pages should be organized in a manner that reflects the rendered website.
Pages can be organized in Sections (root folders) (e.g.: “Blog“, “Project“, etc.).
Assets
Assets are manipulated files (i.e.: resized images, compiled Sass, minified scripts, etc.) with the template asset() function.
Static files
Static files are copied as is in the built site (e.g.: static/file.pdf -> file.pdf).
Data files
Data files are custom variables collections, exposed in templates with site.data.

Files organization

File system tree

Project files organization.

<mywebsite>
├─ pages
|  ├─ blog            <- Section
|  |  ├─ post-1.md    <- Page in Section
|  |  └─ post-2.md
|  ├─ projects
|  |  └─ project-a.md
|  └─ about.md        <- Root page
├─ assets
|  ├─ styles.scss     <- Asset file
|  └─ logo.png
├─ static
|  └─ file.pdf        <- Static file
└─ data
   └─ authors.yml     <- Data collection

Built website tree

Result of the build.

<mywebsite>
└─ _site
   ├─ index.html               <- Generated home page
   ├─ blog/
   |  ├─ index.html            <- Generated list of posts
   |  ├─ post-1/index.html     <- A blog post
   |  └─ post-2/index.html
   ├─ projects/
   |  ├─ index.html
   |  └─ project-a/index.html
   ├─ about/index.html
   ├─ styles.css
   ├─ logo.png
   └─ file.pdf

File based routing

Markdown files in the pages directory enable file based routing. Meaning that adding a pages/my-projects/project-a.md for instance will make it available at /project-a in your browser.

File:
                   pages/my-projects/project-a.md
                        └───── filepath ──────┘
URL:
    ┌───── baseurl ─────┬─────── path ────────┐
     https://example.com/my-projects/project-a/index.html
                        └─ section ─┴─ slug ──┘

Pages

A page is a file made up of a front matter and a body.

Front matter

The front matter is a collection of variables (in key/value format) surrounded by ---.

Example:

---
title: "The title"
date: 2019-02-21
tags: [tag 1, tag 2]
customvar: "Value of customvar"
---

Body

Body is the main content of a page, it could be written in Markdown or in plain text.

Example:

# Header

[toc]

## Sub-Header 1

Lorem ipsum dolor [sit amet](https://example.com), consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
<!-- excerpt -->
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.

## Sub-Header 2

![Description](/image.jpg "Title")

## Sub-Header 3

:::tip
This is an advice.
:::

Markdown

Cecil supports Markdown format, but also Markdown Extra.

Cecil also provides extra features to enhance your content, see below.

Attributes

With Markdown Extra you can set an id, class and custom attributes on certain elements using an attribute block.
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:

## Header {#id .class attribute=value}

You can create a link with the syntax [Text](url) with "url" can be a path, a relative path to a Markdown file, an external URL, etc.

Example:

[Link to a path](/about/)
[Link to a Markdown file](../about.md)
[Link to Cecil website](https://cecil.app)

You can easily create a link to a page with the syntax [Page title](page:page-id).

Example:

[Link to a blog post](page:blog/post-1)

External

By default external links have the following value for rel attribute: "noopener noreferrer nofollow".

Example:

<a href="<url>" rel="noopener noreferrer nofollow">Link to another website</a>

You can change this behavior with pages.body.links.external options.

You can let Cecil tries to turns a link into an embedded content by using the {embed} attribute or by setting the global configuration option pages.body.links.embed.enabled to true.

Example:

[An example YouTube video](https://www.youtube.com/watch?v=Dj-rKHmLp5w){embed}

Cecil can also create a video or audio HTML elements, through the file extension.

Video

Example:

[The video](/video/test.mp4){embed controls poster=/images/video-test.png style="width:100%;"}

Is converted to:

<video src="/video/test.mp4" controls poster="/images/video-test.png" style="width:100%;"></video>
Audio

Example:

[The audio file](/audio/test.mp3){embed controls}

Is converted to:

<audio src="/video/test.mp3" controls></audio>

Images

To add an image, use an exclamation mark (!) followed by alternative description in brackets ([]), and the path or URL to the image in parentheses (()).
You can optionally add a title in quotation marks.

![Alternative description](/image.jpg "Image title")

Lazy loading

Cecil adds the attribute loading="lazy" to each image.

Example:

![](/image.jpg)

Is converted to:

<img src="/image.jpg" loading="lazy">

Decoding

Cecil adds the attribute decoding="async" to each image.

Example:

![](/image.jpg)

Is converted to:

<img src="/image.jpg" decoding="async">

Resize

Each image in the body can be resized automatically by setting a smaller width than the original one, with the extra attribute {width=X} (the resize option must be enabled).

Example:

![](/image.jpg){width=800}

Is converted to:

<img src="/assets/thumbnails/800/image.jpg" width="800" height="600">

Formats

If the formats option is defined, alternatives images are created and added.

Example:

![](/image.jpg)

Could be converted to:

<picture>
  <source srcset="/image.avif" type="image/avif">
  <source srcset="/image.webp" type="image/webp">
  <img src="/image.jpg">
</picture>

Responsive

If the responsive option is enabled, then all images in the body will be automatically "responsived".

Example:

![](/image.jpg){width=800}

If resize and responsive options are enabled, then this Markdown line will be converted to:

<img src="/assets/thumbnails/800/image.jpg" width="800" height="600"
  srcset="/assets/thumbnails/320/image.jpg 320w,
          /assets/thumbnails/640/image.jpg 640w,
          /assets/thumbnails/800/image.jpg 800w"
  sizes="100vw"
>

The sizes attribute take the value of the assets.images.responsive.sizes.default configuration option, but can be changed by creating a new entry named with a class added to the image.

Example:

assets:
  images:
    responsive:
      sizes:
        default: 100vw
        my_class: "(max-width: 800px) 768px, 1024px"
![](/image.jpg){.my_class}

CSS class

You can set a default value to the class attribute of each image with the class option.

Caption

The optional title can be used to create a caption (figcaption) automatically by enabling the caption option.

Example:

![](/images/img.jpg "Title")

Is converted to:

<figure>
  <img src="/image.jpg" title="Title">
  <figcaption>Title</figcaption>
</figure>

Placeholder

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. So the placeholder attribute show a colored background (image dominant color) or a LQIP (Low-Quality Image Placeholder).

Examples:

![](/images/img.jpg){placeholder=color}
![](/images/img.jpg){placeholder=lqip}

Table of contents

You can add a table of contents with the following Markdown syntax:

[toc]

Excerpt

An excerpt can be defined in the body with one of those following tags: excerpt or break.

Example:

Introduction.
<!-- excerpt -->
Main content.

Then use the excerpt_html filter in your template.

Notes

Create a Note block (info, tips, important, etc.).

Example:

:::tip
**Tip:** This is an advice.
:::

Is converted to:

<aside class="note note-tip">
  <p>
    <strong>Tip:</strong> This is an advice.
  </p>
</aside>

Others examples:

Syntax highlight

Enables code block syntax highlighter by setting the pages.body.highlight.enabled option to true.

Example:

```php
echo "Hello world";
```

Is rendered to:

echo "Hello world";

Inserted text

Represents a range of text that has been added.

++text++

Is converted to:

<ins>text</ins>

Variables

The front matter can contains custom variables applied to the current page.

It must be the first thing in the file and must be a valid YAML.

Predefined variables

Variable Description Default value Example
title Title File name without extension. Post 1
layout Template See Lookup rules. 404
date Creation date File creation date (PHP DateTime object). 2019/04/15
updated Modification date File modification date (PHP DateTime object). 2021/11/19
section Section Page's Section. blog
path Path Page's path. blog/post-1
slug Slug Page's slug. post-1
published Published or not true. false
draft Published or not false. true

A page can be added to a menu.

A same page could be added to severals menus, and the position of each entry can be defined with the weight key (the lightest first).

See Menus configuration for details.

Examples:

---
menu: main
---
---
menu: [main, navigation]
---
---
menu:
  main:
    weight: 10
  navigation:
    weight: 20
---

Taxonomy

Taxonomy allows you to connect, relate and classify your website’s content.
In Cecil, these terms are gathered within vocabularies.

Vocabularies are declared in the Configuration.

A page can contain several vocabularies (e.g.: tags) and terms (e.g.: Tag 1).

Example:

---
tags: ["Tag 1", "Tag 2"]
---

Schedule

Schedules pages’ publication.

Example:

The page will be published if current date is >= 2023-02-07:

schedule:
  publish: 2023-02-07

This page is published if current date is <= 2022-04-28:

schedule:
  expiry: 2022-04-28

redirect

As indicated by its name, the redirect variable is used to redirect a page to a dedicated URL.

Example:

---
redirect: "https://arnaudligny.fr"
---

alias

Alias is a redirection to the current page

Example:

---
title: "About"
alias:
  - contact
---

In the previous example contact/ redirects to about/.

output

Defines the output (rendered) format(s). See formats configuration for more details.

Example:

---
output: [html, atom]
---

external

A page with an external variable try to fetch the content of the pointed resource.

Example:

---
external: "https://raw.githubusercontent.com/Cecilapp/Cecil/master/README.md"
---

File prefix

The filename can contain a prefix to define date or weight variables of the page (used by sortby).

date

The date prefix is used to set the date of the page, and must be a valid date format (i.e.: « YYYY-MM-DD »).

Example:

In « 2019-04-23_My blog post.md »:

  • the prefix is « 2019-04-23 »
  • the date of the page is « 2019-04-23 »
  • the title of the page is « My blog post »

weight

The weight prefix is used to set the sort order of the page, and must be a valid integer value.

Example:

In « 1_The first project.md »:

  • the prefix is « 1 »
  • the weight of the page is « 1 »
  • the title of the page is « The first project »

Section

Some dedicated variables can be used in a custom Section (i.e.: <section>/index.md).

sortby

The order of pages in a Section can be changed.

Available values are:

  • date: more recent first
  • title: alphabetic order
  • weight: lightest first

Example:

---
sortby: title
---

More options:

---
sortby:
  variable: date    # "date", "updated", "title" or "weight"
  desc_title: false # used with "date" or "updated" variable value to sort by desc title order if items have the same date
  reverse: false    # reversed if true
---

pagination

Global pagination configuration can be overridden in each Section.

Example:

---
pagination:
  max: 5
  path: "page"
---

cascade

Any variables in cascade are added to the front matter of all sub pages.

Example:

---
cascade:
  banner: image.jpg
---

circular

Set circular to true to enable circular navigation with page.<prev/next>.

Example:

---
circular: true
---

Home page

Like another section, Home page support sortby and pagination configuration.

pagesfrom

Set a valid Section name in pagesfrom to use pages collection from this Section in Home page.

Example:

---
pagesfrom: blog
---

exclude

Set exclude to true to hide a page from list pages (i.e.: Home page, Section, Sitemap, etc.).

Example:

---
exclude: true
---

Multilingual

If your pages are available in multiple languages there is 2 differents ways to define it:

Language in the file name

This is the common way to translate a page from the main language to another language.

You just need to duplicate the reference page and suffix it with the target language code (e.g.: fr).

Example:

├─ about.md    # the reference page
└─ about.fr.md # the french version (`fr`)

Language in the front matter

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 language variable in its front matter.

Example:

---
language: fr
---

Each translated page reference the pages in others languages.

Those pages collection is available in templates with the following variable:

{{ page.translations }}

Dynamic content

With this experimental feature you can use variables and shortcodes in the body.

Display variables

Front matter variables can be use in the body with the template’s syntax {{ page.variable }}.

Example:

--
var: 'value'
---
The value of `var` is {{ page.var }}.

Experimental

Shortcodes

Shortcodes are helpers to create dynamic content.

Experimental

Built-in shortcodes

2 shortcodes are available by default:

YouTube
{{ shortcode.youtube(id) }}
  • id: YouTube video ID

Example:

{{ shortcode.youtube('NaB8JBfE7DY') }}
GitHub Gist
{{ shortcode.gist(user, id) }}
  • user: GitHub user name
  • id: Gist ID

Example:

{{ shortcode.gist('ArnaudLigny', 'fbe791e05b93951ffc1f6abda8ee88f0') }}

Custom shortcode

A shortcode is a Twig macro you must add in a template named shortcodes.twig.

Example:

shortcodes.twig:

{% extends 'extended/macros.twig' %}

{% block macros %}

{# the "foo" shortcode #}
{% macro foo(bar = 'bar') %}
<strong>{{ bar }}</strong>
{% endmacro %}

{% endblock %}

Suggest a modification