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.).
- Pages should be organized in a manner that reflects the rendered website.
- 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}
Links
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)
Link to a page
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.
Embedded links
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 |
menu
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 firsttitle
: alphabetic orderweight
: 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
---
Link translations of a page
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 nameid
: 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 %}