About the script
This is a simple script for creating a static website.
Content is created in text files, using the markdown format, processed by the script and published on the web. That's it.
If this sounds interesting, keep reading to see how I create my own independent part of the web.
The aim is to create simple websites similar to ones generated by these services:
All in the spirit of the IndieWeb.
Table of Contents
Getting started
The script is written in PHP and makes use of:
- Symfony ,
- Twig for templating,
- League/CommonMark,
- Around 800 lines of code.
The site is hosted on Apache2 and used LetsEncrypt for the SSL certificates.
Writing
Adding content
Content is written in Markdown files, with the extension ".md". Markdown is a very simple language for writing content that will be converted to HTML when the page is published. For more details on Markdown, please see GitHub's Markdown guide.
Markdown can also contain HTML, so you can markup your content in plain HTML if you prefer. Mozilla provide a very good HTML reference, if you are new to HTML.
Only files with the extension .md are processed and converted to HTML files.
Front Matter
Each Markdown file can also contain settings specific to that page or post. This is called Front Matter and is always placed at the start of the file.
The Front Matter section of the file has a specific structure which must be followed.
Firstly it always starts and ends with the line: ---.
Secondly it contains attribute / value pairs, one per line, eg: title: Welcome to my blog. The order of the attributes within the Front Matter is not important.
Front Matter is written in YAML. Here is a good guide to YAML, although it might be a little technical for some.
If the attribute contains a list of values, it would be spread over multiple lines, eg:
tags:
- post
- travel
- photo
The Front Matter of a typical post might therefore look something like this:
---
title: Happy New Year
date: 2025-01-01 08:00:00
tags:
- celebration
- new year
- photo
---
The following Front Matter attributes are accepted. Any other attributes will be ignored.
| Attribute | Value |
|---|---|
| title | Free text. |
| date | ISO format YYYY-MM-DD hh:mm:ss eg "2025-01-01 08:00:00". Used for sorting posts. |
| permalink | Any valid URL path, eg "/about/". If not specified the link for the file will be the title. |
| tags | Free text list of tags, one per line. |
| draft | Entry won't be published if draft is "yes" |
| private | Entry won't be linked to if private is "yes" |
| titleprefix | Free text to add before the page name in the page title. |
| navigation | For defining in which menu this page should appear. |
| - menu | Which menu the page appears in. Default templates support "header" and "footer". |
| - title | The text for the menu item. |
| - position | The position of the menu item within the menu. Should be a number. |
| - pre | Text to add before the link for the menu item. |
| - post | Text to add after the link for the menu item. |
| - class | CSS class to add to the menu item, for custom styling. |
| pagination | For defining how lists of posts are created and paged. Is all on one page, no paging |
| - data | Defines tags of the posts to include in this list. Posts must be tagged with this tag to be in this list |
| - size | The size of the pages. If not set, it will show all posts in one list. |
| template | The name of the template file used to process this markdown file. eg if set to "page" it will use the template "page.html.twig" |
Note: you do not need to enclose the value in quotes in the Front Matter section.
A page to be placed in the header menu would look like this:
---
title: About
date: 2025-02-01 08:00:00
navigation:
- menu: header
- title: About me
- position: 3
---
Example markdown file
A typical complete Markdown file might therefore look something like this:
---
title: Happy New Year
date: 2025-01-01 08:00:00
tags:
- celebration
- new year
- photo
---
## Welcome
This is first blog post, I hope you enjoy this site.
<blockquote>Doing It Yourself Rocks!</blockquote>
Folders
Expected folders
These are the default folders. They should not be removed or renamed. More folders can be added without affecting the site.
| Folder | Description |
|---|---|
| assets | Contains static files, such as images, styling (CSS) and scripting (JavaScript). Folder will be copied as is to your website. |
| data | Contains configuration files, in YAML format. |
| feed | Contains code to generate the RSS feed. |
| pages | Contains the site pages written in Markdown. These are standalone pages that will not be processed as posts and therefore won't appear in your feed. |
| posts | Contains the blog posts written in Markdown. Subfolders are allowed to help organise the posts (eg by year), but it won't affect how the posts are processed. |
| themes | Contains template for the site design, using the Twig templating system. |
Default Files
This is a list of specific files. You can edit them, but be sure you understand what you are doing.
| Page | Description |
|---|---|
| robots.txt | Defines how search engines index the site. See Google for further information on robots.txt. Modify only if needed. |
| pages/home.md | Content for the homepage. The homepage markdown file should have the permalink front matter attribute defined as: permalink: /. One page, and only one page, should have this set otherwise the site will not have a homepage and visiting the base URL will return a page not found. |
| pages/404.md | Content to display when a page is not found. The page not found markdown file should have the permalink front matter attribute defined as: permalink: /404.html. |
| feed/index.md | Generates the RSS feed in Atom format. |
| pages/sitemap.md | Generate a sitemap.xml file used by search engines to index the site. Remove if a sitemap is not needed (not recommended). |
Menus
Menus can be defined for the header and footer. This is done in the file "/data/menus.yaml". The syntax of this file is a little more complicated as it is written in YAML.
Learn more about the YAML syntax here.
As an example this file menus.yaml file for a site with two menus, a header and a footer menu. You can add as many menus as you wish, but the default template only knows the header and footer menus.
header:
- title: Home
link: /home/
- title: About
link: /about/
- title: Blog
link: /blog/
- title: /walking
link: /walking/
pre: 'and '
- title: dog 🐕🦺
link: /tagging/dog/
pre: 'the '
post: '. '
- footer:
- title: RSS
link: /feed/
class: ally-statement
- title: Accessibility
link: /accessibility/
- title: Site info
link: /my-site/
If menu items are defined in the menus.yaml file as well as in the Front Matter of specific pages, they are merged based on the position of the items. It is better to not define menu items in both the menus.yaml file and the page Front Matter as the results can be unexpected.
Posts Lists
Lists of posts can be defined using the pagination Front Matter attribute. If your page has this attribute set, the page will display a list of relevant posts. Note though that you need to ensure the page uses a template designed to show posts. By default the template "archive.hmtl.twig" can be used.`
Themes
Themes can be set in the settings.yaml file.
Themes are created in the /templates/ folder. They are build using the Twig template language.
If not set it will take the default templates from the folder: /templates/default/. If that folder does not exist, the site cannot be built.
A theme can extend another theme, as defined by the themeExtends setting.
Shortcodes
Markdown files are sent through the Twig processor before they are themselves rendered to HTML. Any Twig statements in the Markdown file will therefore be processed, including any such statements in the Front Matter.
Examples
The pages.yaml file looks like this:
template: page
permalink: /{ { filename }}/
{ { filename }} will be processed by Twig and replaced with the value of "filename" before the page is handled during the site generation.
If the Twig statement includes a double quote: " then it needs to be hidden from the Markdown converter, else it will be converted to an HTML entity: ".
The best approach is to use single quotes: ' . eg:
{ { include('./templates/default/includes/postslist-fixed.html.twig') } }
If this is not possible then the statement needs to be inside an HTML comment:
<!--{ { include("./templates/default/includes/postslist-fixed.html.twig") }}-->
(Note that for the examples above a space has been added between the opening curly brackets).
The Markdown converter will not convert the content of the HTML commment. Later on the script changes <!--{ { }}--> back to { { }}.
Likewise if there are any other characters in the Twig statement that Markdown will convert, the statement needs to be wrapped in HTML comments. Some example characters include <, > and &.
Metadata
Metadata is information about the site. It is stored in YAML format in the file /data/metadata.yaml. This metadata can be accessed from the site's template, for example to display the title of the site.
This is an example the metadata.yaml file for a basic site:
title: Robin's
url: https://www.robin.is/
urlShort: robin.is
language: en
description: Setup and host your own independent blog
startYear: 2025
relMe: https://github.com/robindotis/
gitHubRepo: https://github.com/robindotis/robin.is/
theme: sky
feed:
subtitle: Setup and host your own independent blog
filename: index.xml
path: /feed/index.xml
id: https://www.robin.is/
author:
name: robindotis
email: admin@robin.is
url: https://www.robin.is/about/
webmention: https://github.com/robindotis/
Settings
Settings are set in the file: /data/setting.yaml. These settings define how the content should be processed. Do not touch unless you are sure you know what you are doing.
Allowed settings are:
| Name | Example | Default | Description |
|---|---|---|---|
| staticDirs | [assets] | [assets] | List of folders containing static files to be copied as is to the output directory. |
| staticFiles | [robots.txt] | [robots.txt,feed/pretty-feed-v3.xsl] | List of static files to be copied as is to the output directory. |
| sourceDirs | [posts] | [posts, pages, feed] | List of folders to be processed. Only Markdown files will be processed. |
| outputDir | /_site/ | /_site/ | The folder in to which the files for the static site will be placed. |
| showSpeed | true | false | A gimmick to output the site generation speed to the home page (the root index.html file). Will replace the token CW_SPEED with the time in seconds and remove any HTML comments surrounding it. HTML comments can therefore be used to hide the token from other pages |
| theme | matrix | default | The name of the folder containing the templates for the site. |
| themeExtends | default | The name of the folder containing the theme that theme builds up on, if any. |
All settings are optional. If they are not provided, defaults will be used.
The default settings.yaml file looks like this:
staticDirs: [assets]
staticFiles: [robots.txt,feed/pretty-feed-v3.xsl]
sourceDirs: [posts, pages, feed]
outputDir: /_site/
References
Below are some excellent links to further technical information and documentation on the technologies used for this site generator.
- Writing the content with Markdown and HTML.
- Styling the site with (CSS).
- Scripting functionality with (JavaScript).
- Modifying the sites structure using the Twig template language.
- For the really adventurous: adapting the site generation engine using PHP.
- RSS and Atom
- Sitemap.xml