Static page generator that uses Twig.

0.3.1 2014-10-02 00:35 UTC

This package is auto-updated.

Last update: 2024-06-06 02:23:15 UTC


Build Status

Genry is a static page generator that uses Twig templating system.

Use cases include:

  • HTML pages loaded from file system
  • hosting environments where no scripting language is available (e.g. no PHP, Ruby, Python, Perl, node.js, etc.)
  • GitHub project and user pages

It's perfect for people who don't have experience with building dynamic websites in server side languages, but want to ease their website building process by eliminating copy/paste code (like navigation HTML) or want to make use of powerful templating language.



  • Get Composer.
  • Run $ composer create-project michaldudek/genry-project suchwebsite -s dev to start a Genry project in suchwebsite dir.
  • Use Twig templates to create your website.
  • Put all your templates inside _templates directory.
  • Run $ php bin/genry generate to generate static HTML files.
  • In templates:
    • When including/extending templates refer to them relative to the _templates dir, e.g. {{ include "subdir/content.html.twig" }} for including _templates/subdir/content.html.twig.
    • Use {{ stylesheet('assets/css/global.css') }} and {{ javascript('assets/js/global.js') }} to add CSS and JS files and {{ stylesheets() }} and {{ javascripts() }} to output them to make sure their URL is always correct and relative to the generated page
    • Import Markdown files using {{ markdown('path/to/file/in/_templates/') }}
  • Templates that filenames end with .inc.html.twig are not rendered directly into HTML files (they are only to be included by other templates)

More information

Write content in Markdown

Genry allows you to import Markdown files directly into HTML files, so you can focus on writing your content, instead of markup.


For comprehensive list of possibilites you should check Twig for Template Designers, but to highlight a few of them:

  • template inheritance - create one layout and use it on every page without repeating yourself
  • includes - include other templates to easily reuse HTML elements you have already created elsewhere - update in one place and it will change everywhere
  • control structure - use features like if / elseif / else, for loops or powerful block system to build your HTML dynamically
  • macros - generate HTML dynamically using macros with arguments based on which you can alter the output
  • variables - store some settings or strings you use often in variables to reuse them easily
  • filters - modify your output by applying filters to them (e.g. format a number, capitalize first word letters in whole sentence, url encode a string)


Genry is built in with Splot Framework (to be released, currently in active development) and can be easily extended through Splot's module system and dependency injection, as well as Twig's extensions feature.


Genry requires PHP 5.4+ command line environment to run which means that it runs just fine on Mac OS X and Linux (I have no idea about Windows, sorry...).

It also requires PHP's package manager - Composer. To install Composer follow their instructions, but in short it's this:

$ curl -sS | php
$ mv composer.phar /usr/local/bin/composer

Composer will help your projects to use the latest version of Genry and will give you access to all of its modules and extensions.


Genry lives directly inside your project, so you don't have to install it on your computer. Simply, when you are about to start a new website project open your Terminal and run this command (where suchwebsite is name/path to your project so you should probably change it to something else):

$ composer create-project michaldudek/genry-project suchwebsite -s dev
$ cd suchwebsite

This will create a basic boilerplate template for your project and some files and dirs that are required for Genry to run:

  • .genry and .cache contain code required by Genry
  • _templates is where your website templates will live (so that they are separate from the main website)
  • assets is a suggested place to put your CSS and JS files, images, videos and any other "assets", but you can put them wherever you want really
  • bin is a directory with executable files and there should be a bin/genry file
  • .gitignore comes prepopulated with some files to ignore by Git, so they don't trash your repository
  • .bowerrc is a suggested configuration for Bower if you want to use it
  • bower.json comes with few suggested packages that you might want to get from Bower to get you started
  • composer.json and composer.lock are files created by Composer that hold information which version of Genry and other PHP libraries you are using

This may seem like quite a lot of files to just start a website, but they are there for a reason and should never get in your way.


You can create a .genry.yml in the root of your project if you want to configure Genry.

This is the default configuration:

cache_dir: .cache
templates_dir: _templates
web_dir: .

    # here you can list additional Genry modules you want available, using their full PHP namespace

Updating and re-installing

If you ever wanted to update Genry to newer version or install it for a Genry project that you deleted from your computer, but pulled it back from somewhere, just use these commands:

  • $ composer update - to update Genry to its latest version
  • $ composer install - to install Genry in a previously "Genry-enabled" project


By default all templates are stored inside the _templates dir so that they don't pollute the root dir and are clearly separated from the generated HTML files. Any *.html.twig files inside that dir (and its subdirs) will be compiled and turned to static HTML files inside the root folder of the project. The directory structure from inside _templates will be kept, e.g.

  • ./_templates/index.html.twig will compile to ./index.html
  • ./_templates/subdir/index.html.twig will compile to ./subdir/index.html
  • ./_templates/subdir/contents.html.twig will compile to ./subdir/contents.html

One exception to this rule are files that end with *.inc.html.twig - these will not be compiled. Their only purpose is to be included inside other templates.

When you include or extend other templates in Twig, always specify their locations relative to the _templates directory.

So, if you have a directory structure like this:


Your index.html.twig template should refer to all other templates like this:

{% extends "" %}

{% block body %}
    {% include "layout/header.html.twig" %}

        {% include "" %}
        {% include "" %}

    {% include "layout/footer.html.twig" %}
{% endblock %}

Always refer to templates relative to the _templates/ dir, even from templates next to each other in the same sub directory.


When you have created your templates compile them by executing this command in the command line in your project folder:

$ php genry generate

Assets Management

Because the generated HTML files will be saved in different locations relative to the root dir while probably extending a single layout template and because your website might not always live in the root dir of your domain (think GitHub project pages which are located at using relative or absolute paths to your JavaScript and CSS files might cause a lot of problems.

For example, if your _templates/ file includes assets like this:

<link rel="stylesheet" href="/assets/css/global.css">
<script type="text/javascript" src="/assets/js/global.js"></script>

It will only work if your website resides in root folder of your domain. If you were to put it in a subdir, e.g. at links to the assets would be broken.

However, if you change them to be relative:

<link rel="stylesheet" href="assets/css/global.css">
<script type="text/javascript" src="assets/js/global.js"></script>

This will only work for files that are located in the root dir of your website. If you made a template _templates/subdir/article.html.twig:

{% extends "" %}

{% block content %}
    Lorem ipsum dolor sit amet.
{% endblock %}

It will compile to a file subdir/article.html and the relativeassets links will also be broken for this one page.

Genry takes care of these two problems if you let him.

Wherever you want to add a CSS or JS file use this notation:

{{ stylesheet('/path/to/css/relative/to/project/dir.css') }}
{{ javascript('/path/to/js/relative/to/project/dir.js') }}

And to output all CSS files (typically in <head>):

{{ stylesheets() }}

And JS files (typically right before </body>):

{{ javascripts() }}

The result will be that Genry will generate URL's to those assets always relative to the generated static HTML file. This way your generated files can safely be put at whatever location on your server as well as opened locally straight from the file system.


Genry comes with few pre-packaged features that don't require any additional modules.


If you want to write your content in Markdown (like this documentation) you can easily import and compile Markdown files inside your templates by simply writing:

{{ markdown('path/to/file/in/templates/') }}

You can also use a Markdown filter:

{{ "[such website](, **much markdown**, such HTML."|markdown }}

Data Objects



Genry is very much work in progress and the core of it has been created in one (albeit long) evening. There are many ideas and features that could be developed for it, but I want to keep it simple. Here is a list of features that are on the roadmap for the nearest future (ie. when need be):

  • More documentation including some recipes, examples and "built with Genry" section as well as information on how to create your own modules.
  • Watching the project for changes and auto regenerating the pages.
  • Minification of CSS and JS files (reusing what is already in Splot Assets Module).


Pull requests, reported issues and any help is welcome. Just keep in mind that this is a strongly personal project and I might have already started working on something that you wanted to do, so before doing any coding work please submit an issue with your idea for discussion.

If you want to develop something for Genry then I will be very happy to help, as there isn't much documentation on this topic yet. Just open an issue and I'll reply to it.