Fantastic Windmill: Documentation

Download Now Version 1.0

Fantastic Windmill (FW) is a static web site generator: it reads content from a set of source files, applies a presentation template to them and saves the output as a set of static HTML files. It is similar in this respect to a lot of other (good) static generators, such as Pelican, nanoc, and Blogofile.

The main difference is that FW relies on a very small set of concepts to provide the same functionality. As a matter of fact, if you know how to write web pages in PHP, then setting up a static web site using FW should be very, very easy. We hereby brag that FW has the shortest documentation of all static web site generators: this single page is all you need to know to use Fantastic Windmill.

Quick links

Why use a static generator?

There exist a number of advantages for the use of a static generator over traditional content management systems (CMS) like Wordpress or Joomla. Since the whole web site is generated in advance, the server only needs to host a set of static HTML files, thereby reducing processing time when a page is requested, and eliminating the security vulnerabilities inherent in the use of a CMS. In addition, the content used to generate the pages is hosted locally in a set of files managed by the user; page contents, blog posts and images are not "trapped" inside the CMS as some obscure database entry that is hard to pull out or move around.

Obviously, some dynamic features present in a CMS are absent from a statically-generated web site. For example, readers cannot post comments or obtain results based on an input query (although some of these functionalities can be achieved using JavaScript and external services, such as Disqus). However, a static generator does create the HTML pages based on content; this means that a newly added blog post will show up in the (static) list of posts (or wherever else) the next time the site is rebuilt. As a rule, one regenerates the web site every time some content changes, and uploads to the web server only the HTML files that have been modified. It turns out that this process is adequate to maintain many a web site.

Quick start

First, download the Fantastic Windmill archive. Then, create a folder that will contain both the source files and output files of your web site. In this example we will call it mysite/. From the downloaded archive, make sure you copy at least the fw/ folder and put it into mysite/. Optionally, you can also copy the Makefile and the templates/ folder from that same archive.

Step 1: write content

Write a set of files in Markdown syntax (note that you can write plain HTML inside a Markdown file); save each file with the .md extension into a folder called mysite/content/. You can put your files into any folder structure inside content/. Each file will become a single page called filename.html in the resulting web site. If a page has links to other documents (e.g. it contains images, or links to other files within your web site), you can use relative links to refer to those documents. Everything that is put into contents/ is intended to be present in the generated web site (with the exception of .md files).

Step 2: write a template

Write a set of template files and put them in a folder called mysite/templates/. A template can be any PHP file; it is called by FW to generate HTML output based on the content of each Markdown document in the content/ folder. FW passes to the template two special variables:

By default, FW looks for a file called base.php to render a page: make sure one of the files has this name. See below to select different template files to render different pages.

Step 3: generate the site

From the mysite/ folder, call

php lib/fw.php

FW will process each input file in the mysite/contents/ folder and output the resulting HTML file in folder mysite/public_html/. You are now ready to upload that folder to your web server.

The previous command only takes care of generating the HTML files, but does not mirror the other files (images, etc.) from contents/ to public_html. You can either do it by yourself, or run

make mirror

to take care of this. The Makefile script can be called with other options as well.

Defining metadata for a page

In addition to its actual contents, each page in the web site can be associated to bits of information, such as a date, an author name, a title or an abstract. You are free to define whatever parameters and values you wish for any page, using YAML notation. Please refer to the YAML web site for help on the (fairly intuitive) syntax of this language.

Inside the page

The first way to define metadata is to add a YAML section at the end of a Markdown input file. The start of YAML declarations is marked by a line containing three dashes (---). Everything that follows will be parsed as YAML and removed from the page for further processing (hence the YAML part does not show up in the final page). Here is a simple example that defines the value of a parameter called author for a page:

# A title for the page

Hello, this is a paragraph inside
the page, with a single sentence.

author: Emmett Brown

FW itself does nothing with the metadata. However, your template files can refer to it. In this example, the value of the author metadata of the current page is accessible to the template by writing $page->data["author"]. You can use it to display the author name; however, as a template file can include any PHP code, you can use this value in any way you like (for example, displaying a different message depending on the author, etc.).

We stress that FW does not impose any parameter of any name (with a single exception, see below). A page does not need to have an author, and that field does not need to be called that way.

Next to the page

The second way to define metadata is to put the YAML declarations in a separate file, with the same name as the input file but with extension .yaml. This is useful if you want to use a document in your web site, but don't want to modify it directly.

In _.yaml

The last way of defining metadata is to put YAML declarations in a file called _.yaml. All pages in the same directory inherit from the metadata present in that file (if present). Hence, if all pages from a directory have the same author, you can put that declaration in _.yaml instead of repeating it for every file.

All together now

Metadata can be defined using a mix of all previous ways. When processing, FW looks for metadata in the following order:

  1. In mysite/contents/_.yaml, if it exists, and then recursively into every _.yaml along the path to the page being processed
  2. In filename.yaml
  3. At the end of

When a metadata field with given name already exists, the newer one overwrites the older one. Hence _.yaml can be used to set default values that can then be overridden by some files or folders. A file _.yaml placed at the root of the site (i.e. into contents/) can be used to define site-wide metadata, such that the site's name, etc. Hence in FW, there is no need for a separate mechanism to define "site" properties vs. "page" properties.

Inferred metadata

Although metadata has no particular meaning in FW, for convenience a couple of fields are auto-generated from a page contents:

Switching templates

Metadata fields in FW have no meaning, except for one. If a page has a metadata field called template, its value will be used by FW as the name of the template file used to render that page (overriding the default value of base.php. Hence, if you put all blog posts into a folder called mysite/contents/posts/, you can put there a file _.yaml with the instruction template: post.php to tell FW to use the post.php template file to render all posts in the folder.

Of course, as with any other metadata field, the template can also be defined on a per-page basis.

Clean URLs

FW can be run with the --clean-urls command-line option. This has for effect of removing the .html extension of all local links inside the pages. Use this option in conjunction with Apache's mod_rewrite module by uploading a .htaccess file at the root of your site, such as this one:

RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^([^\.]+)$ $1.html [NC,L]

Using the example web site

The FW archive is actually an example web site in itself, complete with a contents/ and a templates/ folder. It shows how FW can be used to generate a bilingual web site with a blog section. Look into the templates/ folder to learn how FW's variables can be used for various pages (list of posts, main page, etc.).

Using the Makefile

The archive ships with a sample Makefile you can use to automate some tasks outside of FW.

Why another static generator?

FW achieves roughly the same functionality as most other static web site generators. It distinguishes itself in a couple of design choices that address what we feel are shortcomings of existing tools.

Content structure = output structure

It is very hard to tell many static generators where you want the resulting pages to go. Many of them disregard any folder structure you give to your content and shuffle all pages according to their own (mostly flat) directory scheme. Many times, even the filenames are transformed before outputting the final pages. Mirroring the organization of your input to the output folder generally involves hacks such as including the directory names into page IDs, moving the files around after the generator processed them or even fiddling with the generator's source code. This is even worse if one of your pages is linked to other files (for example: by containing images): those external files must be separated from the page and put into some other ("static") folder. This makes using each page as a stand-alone document difficult.

User-defined metadata

Generators give access to very few metadata about a page (e.g. date, author, title). In addition, this metadata is hard-coded into the tool, which generally won't let you add any other parameter you might want to use in your templates.

Flexible location for page metadata

Not only is metadata relatively limited with existing generators, the location of this metadata is also very rigid: it is generally located at the beginning of an input file, before the actual text. Hence, if one wants to use an input file independently of its use in the web site, it must be trimmed of that leading metadata to become legible. Moreover, no metadata can be shared between e.g. all pages of the same folder. Hence if all pages in a folder have the same author, the author field must be repeated in all the input files.

PHP as the template engine

Most generators let you create templates for pages using one of many HTML template "languages", such as Jinja or Django, which offer only very basic programming constructs for iterating over objects, evaluating conditions, calling external functions or passing arguments. This makes seemingly straightforward templates next to impossible to write --for example, listing up to 5 blog entries with the same ID, but a different language as the current page, sorted by author name.

About the author

Fantastic Windmill was written by Sylvain Hallé, professor at Université du Québec à Chicoutimi, who got tired of using a CMS, was dissatisfied with existing static web site generators, and thinks windmills are fantastic.

© 2013 Sylvain Hallé. Last modified: 2013-01-25